<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="https://perrotta.dev/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Ai on ¬ just serendipity 🍀</title>
    <link>https://perrotta.dev/</link>
    <description>Recent content in Ai on ¬ just serendipity 🍀</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <managingEditor>serendipity@perrotta.dev (Thiago Perrotta)</managingEditor>
    <webMaster>serendipity@perrotta.dev (Thiago Perrotta)</webMaster>
    <copyright>© 2013 - 2026 Thiago Perrotta ·
  a fork of [hugo ʕ•ᴥ•ʔ bear](https://github.com/janraasch/hugo-bearblog/)
</copyright>
    <lastBuildDate>Mon, 27 Jul 2026 18:25:23 +0200</lastBuildDate>
    <atom:link href="https://perrotta.dev/tags/ai/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>pi: asynchronous exit summaries
      </title>
      <link>https://perrotta.dev/2026/07/pi-asynchronous-exit-summaries/</link>
      <pubDate>Mon, 27 Jul 2026 18:18:38 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>coding</category>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/07/pi-asynchronous-exit-summaries/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: &lt;code&gt;ctrl+d&lt;/code&gt; in &lt;a href=&#34;https://github.com/earendil-works/pi&#34;&gt;pi&lt;/a&gt;&#xA;took several seconds to quit.&lt;/p&gt;&#xA;&lt;p&gt;The culprit was &lt;a href=&#34;https://www.npmjs.com/package/pi-memory&#34;&gt;&lt;code&gt;pi-memory&lt;/code&gt;&lt;/a&gt;&amp;rsquo;s&#xA;&lt;code&gt;session_shutdown&lt;/code&gt; handler. It sent one last LLM request to summarize the&#xA;session, wrote its answer to the daily log, then ran &lt;code&gt;qmd update&lt;/code&gt;. Pi awaits&#xA;all shutdown handlers, correctly, so quitting waited for everything:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-diff&#34;&gt;pi.on(&amp;#34;session_shutdown&amp;#34;, async (event, ctx) =&amp;gt; {&#xA;  const result = await generateExitSummary(ctx);&#xA;  fs.writeFileSync(filePath, entry, &amp;#34;utf-8&amp;#34;);&#xA;  await runQmdUpdateNow();&#xA;});&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Making that promise fire-and-forget would not work: Pi exits immediately after&#xA;shutdown, and either the in-flight request keeps Node alive or gets killed&#xA;before it can write anything.&lt;/p&gt;&#xA;&lt;p&gt;Instead, I made the shutdown path write a durable job, synchronously:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-typescript&#34;&gt;const job: ExitSummaryJob = {&#xA;  version: 1,&#xA;  id: randomUUID(),&#xA;  createdAt: new Date().toISOString(),&#xA;  date: todayStr(),&#xA;  reason,&#xA;  sessionId: shortSessionId(ctx.sessionManager.getSessionId()),&#xA;  conversationText: truncated.text,&#xA;  truncated: truncated.truncated,&#xA;  totalChars: truncated.totalChars,&#xA;};&#xA;&#xA;const jobPath = path.join(&#xA;  EXIT_SUMMARY_JOBS_DIR,&#xA;  `${job.createdAt.replace(/[:.]/g, &amp;#34;-&amp;#34;)}-${job.id}.json`,&#xA;);&#xA;fs.writeFileSync(jobPath, `${JSON.stringify(job)}\n`, { encoding: &amp;#34;utf-8&amp;#34;, flag: &amp;#34;wx&amp;#34; });&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The next interactive session starts an unref&amp;rsquo;ed worker. It atomically renames&#xA;one job to claim it, generates summary with active model, writes it back to&#xA;original day&amp;rsquo;s daily log, and deletes job. Failed jobs return to queue. A&#xA;stale claimed job retries after ten minutes.&lt;/p&gt;&#xA;&lt;p&gt;I kept upstream package intact by replacing it with a local package, effectively&#xA;forking it:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% pi remove npm:pi-memory&#xA;Removed npm:pi-memory&#xA;% pi install ~/.pi/agent/local/pi-memory-async&#xA;Installed /Users/thiago.perrotta/.pi/agent/local/pi-memory-async&#xA;% pi list&#xA;User packages:&#xA;  local/pi-memory-async&#xA;    /Users/thiago.perrotta/.pi/agent/local/pi-memory-async&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Jobs live in &lt;code&gt;~/.pi/agent/memory/exit-summary-jobs/&lt;/code&gt;. &lt;code&gt;ctrl+d&lt;/code&gt; only writes one&#xA;JSON file now; summary happens during next session, without blocking exits.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Source code&lt;/strong&gt;:&#xA;&lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/tree/1f175b77a960a460b4e5cc677d6d6390e0cc0530/pi/.pi/agent/local/pi-memory-async&#34;&gt;pi-memory-async&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: pi: asynchronous exit summaries&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/coding/&#34;&gt;#coding&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>pi: update pinned npm packages
      </title>
      <link>https://perrotta.dev/2026/07/pi-update-pinned-npm-packages/</link>
      <pubDate>Mon, 27 Jul 2026 14:28:59 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>coding</category>
      <category>dev</category>
      <category>security</category>
      <guid>https://perrotta.dev/2026/07/pi-update-pinned-npm-packages/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: pin &lt;a href=&#34;https://pi.dev/&#34;&gt;pi&lt;/a&gt; npm packages without giving up&#xA;convenient updates.&lt;/p&gt;&#xA;&lt;p&gt;My&#xA;&lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/blob/master/pi/.pi/agent/settings.json&#34;&gt;&lt;code&gt;settings.json&lt;/code&gt;&lt;/a&gt;&#xA;used to leave some package versions unpinned, until now:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-diff&#34;&gt;     &amp;#34;npm:@heyhuynhgiabuu/pi-diff@0.7.6&amp;#34;,&#xA;-    &amp;#34;npm:@tifan/pi-recap&amp;#34;,&#xA;-    &amp;#34;npm:@tmustier/pi-tab-status&amp;#34;,&#xA;-    &amp;#34;npm:@tintinweb/pi-subagents&amp;#34;&#xA;&amp;#43;    &amp;#34;npm:@tifan/pi-recap@0.4.4&amp;#34;,&#xA;&amp;#43;    &amp;#34;npm:@tmustier/pi-tab-status@0.1.4&amp;#34;,&#xA;&amp;#43;    &amp;#34;npm:@tintinweb/pi-subagents@0.14.3&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Exact versions make package installation reproducible (&amp;amp; safer), but Pi then&#xA;does not automatically pull newer packages.&lt;/p&gt;&#xA;&lt;p&gt;To tackle that, I added a &lt;code&gt;just update-pi&lt;/code&gt; recipe that asks npm for each&#xA;package&amp;rsquo;s current &lt;code&gt;latest&lt;/code&gt; version and writes back an exact pin:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-just&#34;&gt;[doc(&amp;#39;Update pinned Pi npm packages&amp;#39;)]&#xA;[group(&amp;#39;update&amp;#39;)]&#xA;update-pi:&#xA;    #!/usr/bin/env bash&#xA;    set -euo pipefail&#xA;&#xA;    settings=&amp;#34;pi/.pi/agent/settings.json&amp;#34;&#xA;    updates=&amp;#34;{}&amp;#34;&#xA;    while IFS= read -r spec; do&#xA;        if [[ &amp;#34;$spec&amp;#34; =~ ^npm:((@[^/]&amp;#43;/[^@]&amp;#43;)|([^@]&amp;#43;))(@[^@]&amp;#43;)?$ ]]; then&#xA;            package=&amp;#34;${BASH_REMATCH[1]}&amp;#34;&#xA;        else&#xA;            echo &amp;#34;Invalid npm package spec: $spec&amp;#34; &amp;gt;&amp;amp;2&#xA;            exit 1&#xA;        fi&#xA;&#xA;        latest=&amp;#34;$(npm view &amp;#34;$package@latest&amp;#34; version)&amp;#34;&#xA;        pinned=&amp;#34;npm:$package@$latest&amp;#34;&#xA;        updates=&amp;#34;$(jq -cn \&#xA;            --argjson updates &amp;#34;$updates&amp;#34; \&#xA;            --arg spec &amp;#34;$spec&amp;#34; \&#xA;            --arg pinned &amp;#34;$pinned&amp;#34; \&#xA;            &amp;#39;$updates &amp;#43; {($spec): $pinned}&amp;#39;)&amp;#34;&#xA;        echo &amp;#34;✓ $pinned&amp;#34;&#xA;    done &amp;lt; &amp;lt;(jq -r &amp;#39;.packages[] | select(type == &amp;#34;string&amp;#34; and startswith(&amp;#34;npm:&amp;#34;))&amp;#39; &amp;#34;$settings&amp;#34;)&#xA;&#xA;    updated_settings=&amp;#34;$(jq --argjson updates &amp;#34;$updates&amp;#34; \&#xA;        &amp;#39;.packages |= map($updates[.] // .)&amp;#39; &amp;#34;$settings&amp;#34;)&amp;#34;&#xA;    printf &amp;#39;%s\n&amp;#39; &amp;#34;$updated_settings&amp;#34; &amp;gt; &amp;#34;$settings&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It handles every &lt;code&gt;npm:&lt;/code&gt; entry, including scoped packages:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% just update-pi&#xA;✓ npm:@heyhuynhgiabuu/pi-diff@0.7.6&#xA;✓ npm:@heyhuynhgiabuu/pi-pretty@0.6.20&#xA;✓ npm:@tifan/pi-recap@0.4.4&#xA;✓ npm:@tmustier/pi-tab-status@0.1.4&#xA;✓ npm:@tintinweb/pi-subagents@0.14.3&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The aggregate &lt;code&gt;just update&lt;/code&gt; recipe invokes it alongside submodule, prek hook,&#xA;and vendored-file updates.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: pi: update pinned npm packages&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/coding/&#34;&gt;#coding&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/security/&#34;&gt;#security&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>pi: test drive an extension
      </title>
      <link>https://perrotta.dev/2026/07/pi-test-drive-an-extension/</link>
      <pubDate>Sun, 26 Jul 2026 01:24:35 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/07/pi-test-drive-an-extension/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: using &lt;a href=&#34;https://pi.dev/&#34;&gt;pi&lt;/a&gt;, install an extension&#xA;(package) as an one-off, without persisting it, for the sake of test-driving it,&#xA;akin to &lt;a href=&#34;https://pre-commit.com/#pre-commit-try-repo&#34;&gt;&lt;code&gt;pre-commit try-repo&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% pi --help&#xA;[...]&#xA;--extension, -e &amp;lt;path&amp;gt; Load an extension file (can be used multiple times)&#xA;[...]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;For example:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% pi -e npm:@tmustier/pi-usage-extension&#xA;&#xA;added 1 package, and audited 2 packages in 1s&#xA;&#xA;found 0 vulnerabilities&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;then I can run &lt;code&gt;/usage&lt;/code&gt; in that session.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: pi: test drive an extension&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>pi: /btw side-chat
      </title>
      <link>https://perrotta.dev/2026/07/pi-/btw-side-chat/</link>
      <pubDate>Wed, 22 Jul 2026 14:07:54 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>coding</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/07/pi-/btw-side-chat/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/07/pi-auto-retry-stalled-requests/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: mid-task, I want to ask the LLM agent a quick tangential&#xA;question — &amp;ldquo;will this change cause downtime?&amp;rdquo; — without polluting the main&#xA;agent thread.&lt;/p&gt;&#xA;&lt;p&gt;Claude Code has &lt;code&gt;/btw&lt;/code&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/07/pi-/btw-side-chat/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; for exactly this.&#xA;&lt;a href=&#34;https://github.com/earendil-works/pi&#34;&gt;pi&lt;/a&gt; doesn&amp;rsquo;t, but&#xA;&lt;a href=&#34;https://github.com/patriceckhart/pi-btw&#34;&gt;patriceckhart/pi-btw&lt;/a&gt; does, as an&#xA;extension. It opens a side-chat overlay: the LLM gets to see the full main&#xA;thread context and answers, but nothing is written back to the conversation&#xA;history.&lt;/p&gt;&#xA;&lt;p&gt;The upstream extension imports the pre-fork &lt;code&gt;@mariozechner/*&lt;/code&gt; package names,&#xA;which are now deprecated. As such, I use&#xA;&lt;a href=&#34;https://github.com/earendil-works/pi&#34;&gt;earendil-works/pi&lt;/a&gt;. Rather than trust a&#xA;diff I hadn&amp;rsquo;t read, I reimplemented it against the current API, and&#xA;cross-checked against the bundled &lt;code&gt;examples/extensions/summarize.ts&lt;/code&gt; (the&#xA;canonical example for calling the model from an extension):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-typescript&#34;&gt;import { complete } from &amp;#34;@earendil-works/pi-ai/compat&amp;#34;;&#xA;import type { ExtensionAPI, SessionEntry } from &amp;#34;@earendil-works/pi-coding-agent&amp;#34;;&#xA;import { convertToLlm, getMarkdownTheme } from &amp;#34;@earendil-works/pi-coding-agent&amp;#34;;&#xA;&#xA;// ...inside the /btw command handler, once at entry:&#xA;const branch = ctx.sessionManager.getBranch();&#xA;const mainMessages = branch&#xA;  .filter((entry): entry is SessionEntry &amp;amp; { type: &amp;#34;message&amp;#34; } =&amp;gt; entry.type === &amp;#34;message&amp;#34;)&#xA;  .map((entry) =&amp;gt; entry.message);&#xA;const mainLlmMessages = convertToLlm(mainMessages);   // frozen snapshot&#xA;const systemPrompt = ctx.getSystemPrompt();&#xA;&#xA;// ...per question, the side-chat calls the model directly:&#xA;const response = await complete(&#xA;  ctx.model!,&#xA;  { systemPrompt, messages: [...mainLlmMessages, ...btwLlmMessages] },&#xA;  { apiKey: auth.apiKey, headers: auth.headers, env: auth.env, signal },&#xA;);&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The key move is what&amp;rsquo;s &lt;em&gt;missing&lt;/em&gt;: the handler never calls &lt;code&gt;pi.sendMessage()&lt;/code&gt;&#xA;or appends anything. It reads the branch once, talks to the model in an&#xA;&lt;a href=&#34;https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md#custom-ui&#34;&gt;&lt;code&gt;ctx.ui.custom()&lt;/code&gt;&lt;/a&gt;&#xA;overlay, and returns. The main session is untouched, so the next real prompt&#xA;doesn&amp;rsquo;t pay for any of it.&lt;/p&gt;&#xA;&lt;p&gt;Added to &lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/blob/1f42eb6f6632f946c23d1278e7e3f18da78d5de8/pi/.pi/agent/extensions/btw.ts&#34;&gt;&lt;code&gt;~/.pi/agent/extensions/btw.ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;I am no longer using &lt;a href=&#34;https://archlinux.org/&#34;&gt;Arch&lt;/a&gt;, btw (sad!)&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/07/pi-/btw-side-chat/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: pi: /btw side-chat&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/coding/&#34;&gt;#coding&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>pi: auto-retry stalled requests
      </title>
      <link>https://perrotta.dev/2026/07/pi-auto-retry-stalled-requests/</link>
      <pubDate>Wed, 22 Jul 2026 13:45:41 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>coding</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/07/pi-auto-retry-stalled-requests/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/07/pi-cycle-models-backward-with-ctrl-n/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: sometimes a prompt in &lt;a href=&#34;https://github.com/earendil-works/pi&#34;&gt;pi&lt;/a&gt;&#xA;just hangs, as if the network dropped. It never recovers on its own — I have to&#xA;hit &lt;code&gt;Esc&lt;/code&gt; and re-prompt.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s 2026, this symptom should be self-recoverable.&lt;/p&gt;&#xA;&lt;p&gt;Pi already has agent-level retry on transient errors (&lt;code&gt;retry.enabled&lt;/code&gt; defaults&#xA;to &lt;code&gt;true&lt;/code&gt;). The catch is &lt;em&gt;when&lt;/em&gt; it fires: a stalled connection isn&amp;rsquo;t an error&#xA;until the HTTP idle timeout trips, and that defaults to five minutes:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;code&gt;httpIdleTimeoutMs&lt;/code&gt; | number | &lt;code&gt;300000&lt;/code&gt; | HTTP header/body idle timeout in&#xA;milliseconds [&amp;hellip;] Set to &lt;code&gt;0&lt;/code&gt; to disable.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;So pi would have &lt;em&gt;eventually&lt;/em&gt; recovered. I was just quitting long before the&#xA;five-minute clock ran out. Who has patience to wait for &lt;strong&gt;5&lt;/strong&gt; minutes?!&lt;/p&gt;&#xA;&lt;p&gt;:∴ Lower the idle timeout to O(seconds) instead:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;  &amp;#34;httpIdleTimeoutMs&amp;#34;: 30000,&#xA;  &amp;#34;retry&amp;#34;: {&#xA;    &amp;#34;enabled&amp;#34;: true,&#xA;    &amp;#34;maxRetries&amp;#34;: 5,&#xA;    &amp;#34;baseDelayMs&amp;#34;: 2000&#xA;  }&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Dropped into &lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/commit/aae17ba8d7546901820d7474136a628b16d5feee&#34;&gt;&lt;code&gt;~/.pi/agent/settings.json&lt;/code&gt;&lt;/a&gt;, documented in&#xA;&lt;a href=&#34;https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/settings.md&#34;&gt;&lt;code&gt;docs/settings.md&lt;/code&gt;&lt;/a&gt;.&#xA;Now a stall errors out after 30s and &lt;code&gt;pi&lt;/code&gt; retries automatically with exponential&#xA;backoff (2s, 4s, 8s…), up to five attempts. There&amp;rsquo;s no need for &lt;code&gt;Esc&lt;/code&gt; nor&#xA;re-prompting.&lt;/p&gt;&#xA;&lt;p&gt;The idle timer resets on every byte received, so long thinking or a slow stream&#xA;won&amp;rsquo;t trip it — only a genuinely dead connection will. Restart &lt;code&gt;pi&lt;/code&gt; for the&#xA;change to take effect.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: pi: auto-retry stalled requests&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/coding/&#34;&gt;#coding&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>pi: cycle models backward with ctrl&#43;n
      </title>
      <link>https://perrotta.dev/2026/07/pi-cycle-models-backward-with-ctrl-n/</link>
      <pubDate>Wed, 22 Jul 2026 13:23:53 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>coding</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/07/pi-cycle-models-backward-with-ctrl-n/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/07/pi-caveman-mode/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: &lt;a href=&#34;https://github.com/earendil-works/pi&#34;&gt;pi&lt;/a&gt; binds &lt;code&gt;ctrl+p&lt;/code&gt;&#xA;to &lt;code&gt;app.model.cycleForward&lt;/code&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/07/pi-cycle-models-backward-with-ctrl-n/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; by default, but has no default binding to cycle&#xA;backward other than &lt;code&gt;shift+ctrl+p&lt;/code&gt;, which is arguably difficult to remember.&lt;/p&gt;&#xA;&lt;p&gt;Every keybinding in pi is namespaced and overridable via&#xA;&lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/blob/1f42eb6f6632f946c23d1278e7e3f18da78d5de8/pi/.pi/agent/keybindings.json&#34;&gt;&lt;code&gt;~/.pi/agent/keybindings.json&lt;/code&gt;&lt;/a&gt;, documented in&#xA;&lt;a href=&#34;https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/keybindings.md&#34;&gt;&lt;code&gt;docs/keybindings.md&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;  &amp;#34;app.model.cycleBackward&amp;#34;: [&#xA;    &amp;#34;shift&amp;#43;ctrl&amp;#43;p&amp;#34;,&#xA;    &amp;#34;ctrl&amp;#43;n&amp;#34;&#xA;  ]&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;ctrl+n&lt;/code&gt; is also the default for &lt;code&gt;app.session.toggleNamedFilter&lt;/code&gt;, but that&#xA;only fires inside the session picker, not while a model selector or the main&#xA;editor has focus.&lt;/p&gt;&#xA;&lt;p&gt;Run &lt;code&gt;/reload&lt;/code&gt; in pi to pick up the keybinding addition without restarting the&#xA;session.&lt;/p&gt;&#xA;&lt;p&gt;∴ &lt;code&gt;ctrl+p&lt;/code&gt;/&lt;code&gt;ctrl+n&lt;/code&gt; now cycle models forward/backward, matching the readline&#xA;(emacs!) history bindings I already have muscle memory for.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;It cycles through models selected in &lt;code&gt;/scoped-models&lt;/code&gt;.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/07/pi-cycle-models-backward-with-ctrl-n/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: pi: cycle models backward with ctrl+n&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/coding/&#34;&gt;#coding&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>pi: caveman mode
      </title>
      <link>https://perrotta.dev/2026/07/pi-caveman-mode/</link>
      <pubDate>Wed, 22 Jul 2026 12:14:47 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>coding</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/07/pi-caveman-mode/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2025/12/pi/&#34;&gt;Previously&lt;/a&gt;,&#xA;&lt;a href=&#34;https://perrotta.dev/2026/06/caveman-talk-like-caveman-save-tokens/&#34;&gt;previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: adopt &lt;a href=&#34;https://github.com/JuliusBrussee/caveman&#34;&gt;caveman&lt;/a&gt;&#xA;in &lt;a href=&#34;https://github.com/earendil-works/pi&#34;&gt;pi&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Pi isn&amp;rsquo;t one of the 30+ agents caveman auto-detects. The install matrix&#xA;(&lt;code&gt;INSTALL.md&lt;/code&gt;) lists agent detection rules one by one — &lt;code&gt;claude&lt;/code&gt;, &lt;code&gt;cursor&lt;/code&gt;,&#xA;&lt;code&gt;windsurf&lt;/code&gt;, &lt;code&gt;opencode&lt;/code&gt;, &lt;code&gt;openclaw&lt;/code&gt;, etc — and pi isn&amp;rsquo;t in it. Running the&#xA;one-liner installer here would just skip everything silently. Booo!&lt;/p&gt;&#xA;&lt;p&gt;Rather than run someone else&amp;rsquo;s &lt;code&gt;curl | bash&lt;/code&gt; against an agent it wasn&amp;rsquo;t built&#xA;for, &amp;ldquo;&amp;ldquo;&amp;ldquo;I&amp;rdquo;&amp;rdquo;&amp;rdquo; reimplemented the terse-speak part natively, since &lt;code&gt;pi&lt;/code&gt; already ships the&#xA;two primitives needed: &lt;a href=&#34;https://agentskills.io/specification&#34;&gt;skills&lt;/a&gt; and&#xA;&lt;a href=&#34;https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md&#34;&gt;extensions&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;A&#xA;&lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/blob/7c495489141fd6036e4be70de9a065c53f7a8394/pi/.pi/agent/extensions/caveman.ts&#34;&gt;skill&lt;/a&gt;&#xA;for &lt;code&gt;/skill:caveman&lt;/code&gt; documentation, and an extension that rewrites the system&#xA;prompt on every turn via &lt;code&gt;pi.on(&amp;quot;before_agent_start&amp;quot;, (event) =&amp;gt; ...)&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-typescript&#34;&gt;const INSTRUCTIONS = `Caveman mode: on. Respond terse. Drop articles (a/an/the), filler (just/really/basically), pleasantries, hedging. Fragments OK. Short synonyms. Technical terms exact. Pattern: [thing] [action] [reason]. [next step]. Example — not: &amp;#34;Sure! I&amp;#39;d be happy to help you with that.&amp;#34; yes: &amp;#34;Bug in auth middleware. Fix:&amp;#34;&#xA;Boundaries, always: code blocks, commit messages, and PR descriptions stay normal full verbosity, never compressed. Drop caveman style for security warnings, irreversible/destructive actions, or when the user seems confused — resume caveman after.`;&#xA;&#xA;export default function (pi: ExtensionAPI) {&#xA;  let on = true; // auto-on by default, every session&#xA;&#xA;  const applyStatus = (ctx: { ui: { setStatus: (k: string, v?: string) =&amp;gt; void } }) =&amp;gt; {&#xA;    ctx.ui.setStatus(&amp;#34;caveman&amp;#34;, on ? &amp;#34;[caveman]&amp;#34; : undefined);&#xA;  };&#xA;&#xA;  pi.on(&amp;#34;session_start&amp;#34;, async (_event, ctx) =&amp;gt; applyStatus(ctx));&#xA;&#xA;  pi.on(&amp;#34;before_agent_start&amp;#34;, (event) =&amp;gt; {&#xA;    if (!on) return;&#xA;    return { systemPrompt: `${event.systemPrompt}\n\n${INSTRUCTIONS}` };&#xA;  });&#xA;&#xA;  pi.registerCommand(&amp;#34;caveman&amp;#34;, {&#xA;    description: &amp;#34;Toggle caveman terse-response mode: on|off (default: on)&amp;#34;,&#xA;    handler: async (args, ctx) =&amp;gt; {&#xA;      const arg = args.trim().toLowerCase();&#xA;      if (arg === &amp;#34;off&amp;#34; || arg === &amp;#34;stop&amp;#34; || arg === &amp;#34;normal&amp;#34;) on = false;&#xA;      else if (arg === &amp;#34;on&amp;#34; || arg === &amp;#34;&amp;#34;) on = true;&#xA;      else return ctx.ui.notify(`Unknown arg &amp;#34;${arg}&amp;#34;. Use: on | off`, &amp;#34;error&amp;#34;);&#xA;      applyStatus(ctx);&#xA;      ctx.ui.notify(on ? &amp;#34;Caveman mode on.&amp;#34; : &amp;#34;Caveman mode off.&amp;#34;, &amp;#34;info&amp;#34;);&#xA;    },&#xA;  });&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/extensions.md#before_agent_start&#34;&gt;&lt;code&gt;before_agent_start&lt;/code&gt;&lt;/a&gt;&#xA;fires on &lt;strong&gt;every prompt&lt;/strong&gt;, before the agent loop starts, so&#xA;the instructions are re-appended each turn instead of relying on one message&#xA;that could get pruned from context. Dropped in&#xA;&lt;code&gt;~/.pi/agent/extensions/caveman.ts&lt;/code&gt;, auto-discovered, no &lt;code&gt;/reload&lt;/code&gt; needed after&#xA;the first load.&lt;/p&gt;&#xA;&lt;p&gt;Unlike the Claude Code plugin, I skipped &lt;code&gt;lite&lt;/code&gt;/&lt;code&gt;full&lt;/code&gt;/&lt;code&gt;ultra&lt;/code&gt;/&lt;code&gt;wenyan&lt;/code&gt; — I&#xA;called that bloat back in June, and I&amp;rsquo;m not adding it to my own version&#xA;either. On or off is enough.&lt;/p&gt;&#xA;&lt;p&gt;The result, &lt;em&gt;unprompted&lt;/em&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;user&lt;/strong&gt;: caveman on or off now?&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;assistant&lt;/strong&gt;: Caveman: on.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;user&lt;/strong&gt;: how to turn it off?&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;assistant&lt;/strong&gt;: &lt;code&gt;/caveman off&lt;/code&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I also skipped the parts that don&amp;rsquo;t have a pi equivalent: the statusline&#xA;savings counter, &lt;code&gt;/caveman-stats&lt;/code&gt;, the &lt;code&gt;caveman-shrink&lt;/code&gt; MCP proxy that rewrites&#xA;tool descriptions (a proxy that rewrites what an agent sees is exactly the&#xA;kind of thing worth reading before installing). The 40-line extension above&#xA;covers what I actually wanted.&lt;/p&gt;&#xA;&lt;p&gt;One rule baked into both the skill and the extension: code, commits, and PRs&#xA;stay full verbosity, never compressed.&lt;/p&gt;&#xA;&lt;p&gt;This experience was an eye-opener for me to realize how bloated the upstream&#xA;caveman project became.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: pi: caveman mode&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/coding/&#34;&gt;#coding&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ logseq → obsidian
      </title>
      <link>https://perrotta.dev/2026/07/logseq-obsidian/</link>
      <pubDate>Mon, 20 Jul 2026 18:26:33 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <category>pkm</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2026/07/logseq-obsidian/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/07/brew-pin/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: LogSeq v2 is moving its graph format from markdown files&#xA;to a sqlite database:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://discuss.logseq.com/t/whats-new-with-logseq-db-may-16th-2026/35020&#34;&gt;What&amp;rsquo;s New with Logseq DB — May 16th 2026&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://logseq.io/p/e3YDyX5AYr&#34;&gt;Big update: Logseq is splitting into two versions&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This is &lt;em&gt;not OK&lt;/em&gt; for my workflow.&lt;/p&gt;&#xA;&lt;p&gt;The whole point of adopting LogSeq was, just like&#xA;&lt;a href=&#34;https://obsidian.md/&#34;&gt;Obsidian&lt;/a&gt;, the promise of&#xA;managing my notes in plain markdown files.&lt;/p&gt;&#xA;&lt;p&gt;Even though this migration is supposed to improve the performance of the app, it&#xA;ends up breaking a fundamental reason why I decided to use it in the first&#xA;place.&lt;/p&gt;&#xA;&lt;p&gt;Furthermore, the Second Brain app of my choice is supposed to be boring. It is&#xA;a big deal to wake up one day and find that I can no longer open my notes&#xA;graph with the new version of the app. This is a no-go.&lt;/p&gt;&#xA;&lt;p&gt;Well, classic LogSeq (dubbed &amp;ldquo;Logseq OG&amp;rdquo;) will be &lt;a href=&#34;https://github.com/logseq/og&#34;&gt;kept&#xA;around&lt;/a&gt;, but I can only assume that from this&#xA;point on it will become poorly maintained — it will never get the same amount of&#xA;resources and attention as the new version.&lt;/p&gt;&#xA;&lt;p&gt;Also, even if I really wanted to use the new version, it turns out it does not&#xA;work on mobile (iOS), which is a dealbreaker, therefore I would be forced to&#xA;stay stuck with OG for a while. Heck, the iOS app hasn&amp;rsquo;t been updated in 2y&#xA;anyway, and it shows.&lt;/p&gt;&#xA;&lt;p&gt;There will be no hard feelings, this is a peaceful breakup; I enjoyed LogSeq,&#xA;it&amp;rsquo;s simpler and more streamlined than Obsidian; as such, I will keep&#xA;recommending it to most people.&lt;/p&gt;&#xA;&lt;p&gt;That said, I&amp;rsquo;ve always been pondering whether to switch back to Obsidian.&#xA;There&amp;rsquo;s no doubt that Obsidian is more actively maintained and better suited for&#xA;Gen AI / LLM workflows these days (see &lt;a href=&#34;https://obsidian.md/cli&#34;&gt;Obsidian CLI&lt;/a&gt;&#xA;for starters).&lt;/p&gt;&#xA;&lt;p&gt;Why did I switch to LogSeq from Obsidian in the first place? Because Obsidian&#xA;was too much for me. It was more complicated (in terms of its feature set) than&#xA;warranted for my purposes. It offered more than I needed. That&amp;rsquo;s not necessarily&#xA;a bad thing. It&amp;rsquo;s like saying (hypothetically) &amp;ldquo;I prefer &lt;code&gt;nano&lt;/code&gt; instead of&#xA;&lt;code&gt;vim&lt;/code&gt;&amp;rdquo;, or that I prefer to live in a studio apartment than in a 3-bedroom&#xA;house.&lt;/p&gt;&#xA;&lt;p&gt;Obsidian won&amp;rsquo;t let me down in terms of changing its file format: &lt;a href=&#34;https://stephango.com/file-over-app&#34;&gt;file over&#xA;app&lt;/a&gt; is one of their core&#xA;&lt;a href=&#34;https://stephango.com/self-guarantee&#34;&gt;promises&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;File over app is a philosophy: if you want to create digital artifacts that&#xA;last, they must be files you can control, in formats that are easy to retrieve&#xA;and read. Use tools that give you this freedom.&lt;/p&gt;&#xA;&lt;p&gt;File over app is an appeal to tool makers: accept that all software is&#xA;ephemeral, and give people ownership over their data.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;This is very important. My Second Brain app must not lock me in. LogSeq, upon&#xA;the switch to a sqlite database, breaks this invariant. I want — I need — boring&#xA;markdown files. Do not break the beauty and simplicity of this setup.&lt;/p&gt;&#xA;&lt;h2 id=&#34;migration&#34;&gt;&#xA;  Migration&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/07/logseq-obsidian/#migration&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;LogSeq and Obsidian are similar but not identical.&lt;/p&gt;&#xA;&lt;p&gt;In order to bridge the gap, a small python script (drafted by Claude Fable 5,&#xA;reviewed by me) walked the existing LogSeq Graph and wrote to a fresh Obsidian&#xA;Vault, leaving the source untouched, should I decide to roll back.&lt;/p&gt;&#xA;&lt;p&gt;These are some mappings (LogSeq → Obsidian):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;journals/2024_03_04.md         -&amp;gt;  journals/2024-03-04.md&#xA;pages/Foo___Bar.md             -&amp;gt;  Foo/Bar.md          (namespaces)&#xA;- TODO buy milk                -&amp;gt;  - [ ] buy milk&#xA;- DOING ...                    -&amp;gt;  - [/] ...&#xA;- DONE ...                     -&amp;gt;  - [x] ...&#xA;[[Feb 9th, 2026]]              -&amp;gt;  [[2026-02-09]]&#xA;((67ea7dba-3200-...))          -&amp;gt;  [[2025-03-31#^67ea7dba]]&#xA;{{embed ((67ea7dba-3200-...))}} -&amp;gt; ![[2025-03-31#^67ea7dba]]&#xA;{{video https://...}}          -&amp;gt;  plain URL&#xA;id:: 67ea7dba-3200-...         -&amp;gt;  ^67ea7dba block anchor (when referenced)&#xA;collapsed:: true, :LOGBOOK:    -&amp;gt;  dropped&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Plus one line of config so that the LogSeq journals become Obsidian daily notes:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;    &amp;#34;folder&amp;#34;: &amp;#34;journals&amp;#34;,&#xA;    &amp;#34;format&amp;#34;: &amp;#34;YYYY-MM-DD&amp;#34;&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;and then I spent some time trying to dumb down Obsidian, disabling core&#xA;plug-ins I do not need at this time. There&amp;rsquo;s no need for community plug-ins for&#xA;now (if ever).&lt;/p&gt;&#xA;&lt;p&gt;So far, I only migrated my corp (work) notes. I&amp;rsquo;ll need to migrate my personal&#xA;PKM as well, but I am happy to simply pilot this migration at work first, so&#xA;that I don&amp;rsquo;t get to regret twice.&lt;/p&gt;&#xA;&lt;p&gt;The migration script:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;#!/usr/bin/env python3&#xA;&amp;#34;&amp;#34;&amp;#34;Migrate LogSeq graph -&amp;gt; Obsidian vault. Source is never modified.&amp;#34;&amp;#34;&amp;#34;&#xA;import re&#xA;import shutil&#xA;from pathlib import Path&#xA;&#xA;SRC = Path(&amp;#34;/Users/thiago.perrotta/Library/Mobile Documents/iCloud~com~logseq~logseq/{redacted}&amp;#34;)&#xA;DST = Path(&amp;#34;/Users/thiago.perrotta/Library/Mobile Documents/iCloud~md~obsidian/{redacted}&amp;#34;)&#xA;&#xA;UUID = r&amp;#34;[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}&amp;#34;&#xA;MONTHS = {m: i &amp;#43; 1 for i, m in enumerate(&#xA;    [&amp;#34;Jan&amp;#34;, &amp;#34;Feb&amp;#34;, &amp;#34;Mar&amp;#34;, &amp;#34;Apr&amp;#34;, &amp;#34;May&amp;#34;, &amp;#34;Jun&amp;#34;, &amp;#34;Jul&amp;#34;, &amp;#34;Aug&amp;#34;, &amp;#34;Sep&amp;#34;, &amp;#34;Oct&amp;#34;, &amp;#34;Nov&amp;#34;, &amp;#34;Dec&amp;#34;])}&#xA;&#xA;MARKER_MAP = {&#xA;    &amp;#34;TODO&amp;#34;: &amp;#34;[ ]&amp;#34;, &amp;#34;LATER&amp;#34;: &amp;#34;[ ]&amp;#34;, &amp;#34;WAITING&amp;#34;: &amp;#34;[ ]&amp;#34;,&#xA;    &amp;#34;DOING&amp;#34;: &amp;#34;[/]&amp;#34;, &amp;#34;NOW&amp;#34;: &amp;#34;[/]&amp;#34;, &amp;#34;IN-PROGRESS&amp;#34;: &amp;#34;[/]&amp;#34;,&#xA;    &amp;#34;DONE&amp;#34;: &amp;#34;[x]&amp;#34;,&#xA;    &amp;#34;CANCELED&amp;#34;: &amp;#34;[-]&amp;#34;, &amp;#34;CANCELLED&amp;#34;: &amp;#34;[-]&amp;#34;,&#xA;}&#xA;&#xA;&#xA;def journal_name(stem: str) -&amp;gt; str:&#xA;    return stem.replace(&amp;#34;_&amp;#34;, &amp;#34;-&amp;#34;)&#xA;&#xA;&#xA;def dest_rel(src_file: Path) -&amp;gt; Path:&#xA;    &amp;#34;&amp;#34;&amp;#34;Map a source md file to its vault-relative destination path.&amp;#34;&amp;#34;&amp;#34;&#xA;    if src_file.parent.name == &amp;#34;journals&amp;#34;:&#xA;        return Path(&amp;#34;journals&amp;#34;) / (journal_name(src_file.stem) &amp;#43; &amp;#34;.md&amp;#34;)&#xA;    # namespace pages: A___B.md -&amp;gt; A/B.md; everything else under pages/&#xA;    parts = src_file.stem.split(&amp;#34;___&amp;#34;)&#xA;    return Path(*parts[:-1]) / (parts[-1] &amp;#43; &amp;#34;.md&amp;#34;) if len(parts) &amp;gt; 1 else Path(&amp;#34;pages&amp;#34;) / src_file.name&#xA;&#xA;&#xA;def page_ref(src_file: Path) -&amp;gt; str:&#xA;    &amp;#34;&amp;#34;&amp;#34;Wiki-link target for a source file (what goes inside [[...]]).&amp;#34;&amp;#34;&amp;#34;&#xA;    if src_file.parent.name == &amp;#34;journals&amp;#34;:&#xA;        return journal_name(src_file.stem)&#xA;    return &amp;#34;/&amp;#34;.join(src_file.stem.split(&amp;#34;___&amp;#34;))&#xA;&#xA;&#xA;def collect_ids():&#xA;    &amp;#34;&amp;#34;&amp;#34;uuid -&amp;gt; (link target, anchor) for every id:: definition; also which uuids are referenced.&amp;#34;&amp;#34;&amp;#34;&#xA;    defined, referenced = {}, set()&#xA;    for f in sorted(SRC.glob(&amp;#34;pages/*.md&amp;#34;)) &amp;#43; sorted(SRC.glob(&amp;#34;journals/*.md&amp;#34;)):&#xA;        text = f.read_text(encoding=&amp;#34;utf-8&amp;#34;)&#xA;        for m in re.finditer(rf&amp;#34;^\s*id:: ({UUID})\s*$&amp;#34;, text, re.M):&#xA;            defined[m.group(1)] = (page_ref(f), m.group(1)[:8])&#xA;        for m in re.finditer(rf&amp;#34;\(\(({UUID})\)\)&amp;#34;, text):&#xA;            referenced.add(m.group(1))&#xA;    return defined, referenced&#xA;&#xA;&#xA;def convert(text: str, defined, referenced) -&amp;gt; str:&#xA;    lines = text.split(&amp;#34;\n&amp;#34;)&#xA;    out = []&#xA;    in_fence = False&#xA;    in_logbook = False&#xA;&#xA;    def resolve_ref(m):&#xA;        uuid = m.group(1)&#xA;        if uuid in defined:&#xA;            target, anchor = defined[uuid]&#xA;            return f&amp;#34;[[{target}#^{anchor}]]&amp;#34;&#xA;        return m.group(0)&#xA;&#xA;    def resolve_embed(m):&#xA;        uuid = m.group(1)&#xA;        if uuid in defined:&#xA;            target, anchor = defined[uuid]&#xA;            return f&amp;#34;![[{target}#^{anchor}]]&amp;#34;&#xA;        return m.group(0)&#xA;&#xA;    def date_link(m):&#xA;        mon, day, year = m.group(1), int(m.group(2)), int(m.group(4))&#xA;        return f&amp;#34;[[{year:04d}-{MONTHS[mon]:02d}-{day:02d}]]&amp;#34;&#xA;&#xA;    pending_merge_indent = None  # indent of an empty bullet awaiting its continuation line&#xA;&#xA;    for line in lines:&#xA;        stripped = line.strip()&#xA;&#xA;        # merge continuation text into a bullet whose first line was a property&#xA;        if pending_merge_indent is not None:&#xA;            m = re.match(rf&amp;#34;^{re.escape(pending_merge_indent)}\s\s?(\S.*)$&amp;#34;, line)&#xA;            pending_merge_indent = None&#xA;            if m and out:&#xA;                out[-1] = out[-1] &amp;#43; m.group(1)&#xA;                continue&#xA;&#xA;        # LogSeq opens fences on bullet lines (&amp;#34;- ```lang&amp;#34;), closes with bare &amp;#34;```&amp;#34;&#xA;        if re.match(r&amp;#34;^\s*(?:[-*&amp;#43;]\s&amp;#43;)?```&amp;#34;, line):&#xA;            in_fence = not in_fence&#xA;            out.append(line)&#xA;            continue&#xA;        if in_fence:&#xA;            out.append(line)&#xA;            continue&#xA;&#xA;        # LOGBOOK drawers&#xA;        if stripped == &amp;#34;:LOGBOOK:&amp;#34;:&#xA;            in_logbook = True&#xA;            continue&#xA;        if in_logbook:&#xA;            if stripped == &amp;#34;:END:&amp;#34;:&#xA;                in_logbook = False&#xA;            continue&#xA;&#xA;        # bullet-form property lines: block whose first line is the property itself&#xA;        # (&amp;#34;- collapsed:: true&amp;#34; with real content on the continuation line below)&#xA;        m = re.match(rf&amp;#34;^(\s*)- (collapsed:: (?:true|false)|logseq\.order-list-type:: number|id:: ({UUID}))\s*$&amp;#34;, line)&#xA;        if m:&#xA;            indent = m.group(1)&#xA;            uuid = m.group(3)&#xA;            if uuid and uuid in referenced:&#xA;                out.append(f&amp;#34;{indent}- ^{uuid[:8]}&amp;#34;)&#xA;            else:&#xA;                out.append(f&amp;#34;{indent}- &amp;#34;)&#xA;                pending_merge_indent = indent&#xA;            continue&#xA;&#xA;        # property lines&#xA;        m = re.match(rf&amp;#34;^\s*id:: ({UUID})\s*$&amp;#34;, line)&#xA;        if m:&#xA;            uuid = m.group(1)&#xA;            if uuid in referenced and out:&#xA;                # anchor goes at end of the block&amp;#39;s first line&#xA;                for i in range(len(out) - 1, -1, -1):&#xA;                    if out[i].strip():&#xA;                        out[i] = out[i].rstrip() &amp;#43; f&amp;#34; ^{uuid[:8]}&amp;#34;&#xA;                        break&#xA;            continue&#xA;        if re.match(r&amp;#34;^\s*collapsed:: (true|false)\s*$&amp;#34;, line):&#xA;            continue&#xA;        if re.match(r&amp;#34;^\s*logseq\.order-list-type:: number\s*$&amp;#34;, line):&#xA;            # convert the previous bullet line to a numbered item; number it by&#xA;            # walking back past deeper lines to the previous same-indent sibling&#xA;            for i in range(len(out) - 1, -1, -1):&#xA;                bm = re.match(r&amp;#34;^(\s*)- (.*)$&amp;#34;, out[i])&#xA;                if bm:&#xA;                    indent = bm.group(1)&#xA;                    n = 1&#xA;                    for j in range(i - 1, -1, -1):&#xA;                        if not out[j].strip():&#xA;                            continue&#xA;                        lead = out[j][: len(out[j]) - len(out[j].lstrip())]&#xA;                        if len(lead) &amp;gt; len(indent):&#xA;                            continue  # child or continuation line&#xA;                        if lead == indent:&#xA;                            nm = re.match(rf&amp;#34;^{re.escape(indent)}(\d&amp;#43;)\. &amp;#34;, out[j])&#xA;                            n = int(nm.group(1)) &amp;#43; 1 if nm else 1&#xA;                        break&#xA;                    out[i] = f&amp;#34;{indent}{n}. {bm.group(2)}&amp;#34;&#xA;                    break&#xA;            continue&#xA;&#xA;        # task markers on bullet lines (not headings)&#xA;        line = re.sub(&#xA;            r&amp;#34;^(\s*)- (TODO|LATER|WAITING|DOING|NOW|IN-PROGRESS|DONE|CANCELED|CANCELLED)\s&amp;#43;&amp;#34;,&#xA;            lambda m: f&amp;#34;{m.group(1)}- {MARKER_MAP[m.group(2)]} &amp;#34;,&#xA;            line,&#xA;        )&#xA;&#xA;        # drop LogSeq priority markers&#xA;        line = re.sub(r&amp;#34;\[#[A-C]\]\s*&amp;#34;, &amp;#34;&amp;#34;, line)&#xA;&#xA;        # embeds and block refs&#xA;        line = re.sub(rf&amp;#34;\{{\{{embed \(\(({UUID})\)\)\}}\}}&amp;#34;, resolve_embed, line)&#xA;        line = re.sub(r&amp;#34;\{\{embed \[\[([^]]&amp;#43;)\]\]\}\}&amp;#34;, r&amp;#34;![[\1]]&amp;#34;, line)&#xA;        line = re.sub(rf&amp;#34;\(\(({UUID})\)\)&amp;#34;, resolve_ref, line)&#xA;        line = re.sub(r&amp;#34;\{\{video ([^}]&amp;#43;)\}\}&amp;#34;, r&amp;#34;\1&amp;#34;, line)&#xA;&#xA;        # date links: [[Feb 9th, 2026]] -&amp;gt; [[2026-02-09]]&#xA;        line = re.sub(&#xA;            r&amp;#34;\[\[(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{1,2})(st|nd|rd|th), (\d{4})\]\]&amp;#34;,&#xA;            date_link, line)&#xA;&#xA;        # asset paths&#xA;        line = line.replace(&amp;#34;](../assets/&amp;#34;, &amp;#34;](assets/&amp;#34;)&#xA;&#xA;        out.append(line)&#xA;&#xA;    result = &amp;#34;\n&amp;#34;.join(out)&#xA;    if result.strip() == &amp;#34;-&amp;#34;:  # LogSeq empty-page placeholder&#xA;        result = &amp;#34;&amp;#34;&#xA;    return result&#xA;&#xA;&#xA;def main():&#xA;    defined, referenced = collect_ids()&#xA;    orphans = referenced - set(defined)&#xA;    if orphans:&#xA;        print(f&amp;#34;WARNING: refs without target: {orphans}&amp;#34;)&#xA;&#xA;    written = 0&#xA;    for f in sorted(SRC.glob(&amp;#34;pages/*.md&amp;#34;)) &amp;#43; sorted(SRC.glob(&amp;#34;journals/*.md&amp;#34;)):&#xA;        rel = dest_rel(f)&#xA;        dst = DST / rel&#xA;        dst.parent.mkdir(parents=True, exist_ok=True)&#xA;        dst.write_text(convert(f.read_text(encoding=&amp;#34;utf-8&amp;#34;), defined, referenced),&#xA;                       encoding=&amp;#34;utf-8&amp;#34;)&#xA;        written &amp;#43;= 1&#xA;&#xA;    assets_dst = DST / &amp;#34;assets&amp;#34;&#xA;    assets_dst.mkdir(exist_ok=True)&#xA;    copied = 0&#xA;    for a in SRC.glob(&amp;#34;assets/*&amp;#34;):&#xA;        if a.name == &amp;#34;.DS_Store&amp;#34;:&#xA;            continue&#xA;        shutil.copy2(a, assets_dst / a.name)&#xA;        copied &amp;#43;= 1&#xA;&#xA;    print(f&amp;#34;wrote {written} notes, copied {copied} assets&amp;#34;)&#xA;&#xA;&#xA;if __name__ == &amp;#34;__main__&amp;#34;:&#xA;    main()&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: logseq → obsidian&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/serenity/&#34;&gt;#serenity&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>claude code: replace a hand-rolled loop with /goal
      </title>
      <link>https://perrotta.dev/2026/07/claude-code-replace-a-hand-rolled-loop-with-/goal/</link>
      <pubDate>Thu, 16 Jul 2026 13:44:25 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>coding</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/07/claude-code-replace-a-hand-rolled-loop-with-/goal/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/06/claude-code-ship-your-skills-as-a-plugin-marketplace/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: one of my skills, &lt;code&gt;/pr-pass&lt;/code&gt;, was a hand-rolled loop —&#xA;push, poll CI, fix a failure, re-push, repeat, bail after five iterations.&lt;/p&gt;&#xA;&lt;p&gt;It works quite well, and it&amp;rsquo;s one of my most used skills.&lt;/p&gt;&#xA;&lt;p&gt;That said, recently Claude Code shipped&#xA;&lt;a href=&#34;https://code.claude.com/docs/en/goal&#34;&gt;&lt;code&gt;/goal&lt;/code&gt;&lt;/a&gt; (in v2.1.139), which is exactly&#xA;that loop, packaging it as a primitive. So the skill was reimplementing something&#xA;the harness &lt;em&gt;now&lt;/em&gt; does natively.&lt;/p&gt;&#xA;&lt;p&gt;In fact,&#xA;&lt;a href=&#34;https://newsletter.pragmaticengineer.com/p/what-is-loop-engineering&#34;&gt;most&lt;/a&gt;&#xA;harnesses ship &lt;code&gt;/goal&lt;/code&gt; natively these days.&lt;/p&gt;&#xA;&lt;p&gt;We shall&#xA;&lt;a href=&#34;https://github.com/thiagowfx/skills/commit/322d4523f10c8ab1fa3cf8eeb95d776c6debf17c&#34;&gt;refactor&lt;/a&gt;!&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;/goal&lt;/code&gt; sets a completion condition. After each turn a fast model checks whether&#xA;it holds; if not, Claude starts another turn on its own. It auto-clears once the&#xA;condition is met. From the docs:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The &lt;code&gt;/goal&lt;/code&gt; command sets a completion condition and Claude keeps working&#xA;toward it without you prompting each step. After each turn, a small fast model&#xA;checks whether the condition holds. If not, Claude starts another turn instead&#xA;of returning control to you.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;That deletes three things the old skill hand-built: the &lt;code&gt;Monitor&lt;/code&gt; poll waiting&#xA;on CI state, the &amp;ldquo;go back to Step 1&amp;rdquo; loop, and the max-5-iterations guard. The&#xA;guard becomes a clause in the condition itself:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;/goal every check on this PR has passed (gh pr checks shows no FAILURE&#xA;and no PENDING), or stop after 5 turns&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;One catch worth knowing before reaching for &lt;code&gt;/goal&lt;/code&gt;: the evaluator (tester?) is&#xA;a fresh model that &lt;strong&gt;only reads the transcript&lt;/strong&gt;. It does not run &lt;code&gt;gh&lt;/code&gt; or read&#xA;files.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;It does not call tools, so it can only judge what Claude has already surfaced&#xA;in the conversation.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;So the condition has to be something Claude&amp;rsquo;s own output demonstrates. The skill&#xA;now says to paste the &lt;code&gt;gh pr checks&lt;/code&gt; result into the reply every turn, so the&#xA;evaluator has a CI state to judge against. Otherwise the goal would have never&#xA;resolved thus it would have looped forever.&lt;/p&gt;&#xA;&lt;p&gt;Another gotcha: &lt;code&gt;/goal&lt;/code&gt; doesn&amp;rsquo;t touch permissions. Each turn&amp;rsquo;s &lt;code&gt;git push&lt;/code&gt;&#xA;still prompts unless paired it with &lt;a href=&#34;https://code.claude.com/docs/en/auto-mode-config&#34;&gt;auto&#xA;mode&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The lesson generalizes past this one skill: whenever the harness grows a&#xA;primitive, the custom code that predates it becomes technical debt. &lt;code&gt;/loop&lt;/code&gt;,&#xA;Stop hooks, and &lt;code&gt;/goal&lt;/code&gt; now cover most of the &amp;ldquo;keep going until X&amp;rdquo; constructs I&#xA;used previously.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: claude code: replace a hand-rolled loop with /goal&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/coding/&#34;&gt;#coding&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>when Gen AI cites docs that don&#39;t exist
      </title>
      <link>https://perrotta.dev/2026/07/when-gen-ai-cites-docs-that-dont-exist/</link>
      <pubDate>Thu, 16 Jul 2026 12:34:22 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2026/07/when-gen-ai-cites-docs-that-dont-exist/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Today in AGI&lt;/strong&gt;: two Claude agents, same annotation, opposite answers.&lt;/p&gt;&#xA;&lt;p&gt;I had a PR touching an ArgoCD &lt;code&gt;PostSync&lt;/code&gt; hook. Ordering hooks within a phase&#xA;needs an annotation, so I asked; Claude Code (Opus 4.8) and Claude in GitHub&#xA;disagreed:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Claude Code: &lt;code&gt;argocd.argoproj.io/hook-weight&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; exist.&lt;/li&gt;&#xA;&lt;li&gt;Claude in GitHub: it &lt;strong&gt;does&lt;/strong&gt; exist.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Both stated it flatly. So I pushed the GitHub agent, and it doubled down —&#xA;citing documentation(!):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;This claim is incorrect. &lt;code&gt;argocd.argoproj.io/hook-weight&lt;/code&gt; is a documented&#xA;ArgoCD annotation for controlling hook execution order within a phase. From&#xA;the ArgoCD resource hooks documentation:&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Citing non-existent docs is the clanker equivalent of pulling rank.&lt;/p&gt;&#xA;&lt;p&gt;Confident. Sourced. Wrong. The actual annotation for ordering is&#xA;&lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/&#34;&gt;&lt;code&gt;argocd.argoproj.io/sync-wave&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;They are defined by the &lt;code&gt;argocd.argoproj.io/sync-wave&lt;/code&gt; annotation. The value&#xA;is an integer that defines the ordering.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;metadata:&#xA;  annotations:&#xA;    argocd.argoproj.io/sync-wave: &amp;#34;5&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;There is no &lt;code&gt;hook-weight&lt;/code&gt;. The &amp;ldquo;documentation&amp;rdquo; it quoted from doesn&amp;rsquo;t say what&#xA;it says it says.&lt;/p&gt;&#xA;&lt;p&gt;Eventually it folded:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;You are correct, and I apologize for the confident but incorrect claim in&#xA;round 3.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Round 3. It took three rounds and a fabricated citation before the model&#xA;conceded. The failure mode isn&amp;rsquo;t the hallucination — it&amp;rsquo;s the escalation to&#xA;&lt;code&gt;&amp;quot;&amp;quot;&amp;quot;docs&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt; as authority to defend it.&lt;/p&gt;&#xA;&lt;p&gt;Same model family, same question, one right and one wrong. Verify against the&#xA;upstream source, not against the more confident agent.&lt;/p&gt;&#xA;&lt;p&gt;Human-in-the-loop is still very much needed, folks.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: when Gen AI cites docs that don&#39;t exist&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ cmux
      </title>
      <link>https://perrotta.dev/2026/07/cmux/</link>
      <pubDate>Tue, 07 Jul 2026 14:35:14 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <category>ghostty</category>
      <guid>https://perrotta.dev/2026/07/cmux/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://cmux.com/&#34;&gt;cmux&lt;/a&gt; is the best implementation I&amp;rsquo;ve&#xA;seen for agent orchestrators apps like &lt;a href=&#34;https://www.conductor.build/&#34;&gt;Conductor&lt;/a&gt;,&#xA;&lt;a href=&#34;https://github.com/pingdotgg/t3code&#34;&gt;T3 Code&lt;/a&gt;,&#xA;&lt;a href=&#34;https://github.com/patrickdappollonio/dux&#34;&gt;Dux&lt;/a&gt;, and friends:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Open source Ghostty-based macOS terminal with vertical tabs and notifications&#xA;for AI coding agents. Built for multitasking, organization, and&#xA;programmability.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;It&amp;rsquo;s built on top of &lt;a href=&#34;https://ghostty.org/&#34;&gt;Ghostty&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/07/cmux/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; and it&amp;rsquo;s absolutely&#xA;amazing. It&amp;rsquo;s effectively better than what I attempted to build once during an&#xA;on-site hackathon wiring Claude Code sessions to&#xA;&lt;a href=&#34;https://obsidian.md/&#34;&gt;Obsidian&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The invariant I care about the most:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;restart your computer&lt;/li&gt;&#xA;&lt;li&gt;reopen &lt;code&gt;$APP&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;automatically restore every claude code session: layout &amp;amp; history preserved,&#xA;scrollback intact&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&amp;hellip;is accomplished with fine elegance by &lt;code&gt;cmux&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;There&amp;rsquo;s no need to manually fiddle with &lt;code&gt;tmux&lt;/code&gt; / &lt;code&gt;zellij&lt;/code&gt; resurrection or alike.&lt;/p&gt;&#xA;&lt;p&gt;Pair it with &lt;a href=&#34;https://perrotta.dev/2026/05/worktrunk/&#34;&gt;worktrunk&lt;/a&gt; (the &lt;code&gt;wt&lt;/code&gt; CLI) for&#xA;bonus points. Its&#xA;&lt;a href=&#34;https://worktrunk.dev/tips-patterns/#cmux-workspace-per-worktree&#34;&gt;integration&lt;/a&gt;&#xA;is well-supported, achieving one cmux workspace per git worktree. For the time&#xA;being I&amp;rsquo;m still invoking &lt;code&gt;wt&lt;/code&gt; manually though, because that gives me more&#xA;control.&lt;/p&gt;&#xA;&lt;p&gt;It is very &lt;a href=&#34;https://cmux.com/docs/configuration&#34;&gt;customizable&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Desirable side effect: existing &lt;code&gt;ghostty&lt;/code&gt; settings are automatically&#xA;inherited. They aren&amp;rsquo;t duplicated — they are effectively reused, which is&#xA;superb.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/07/cmux/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: cmux&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/ghostty/&#34;&gt;#ghostty&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ claude code: ship your skills as a plugin marketplace
      </title>
      <link>https://perrotta.dev/2026/06/claude-code-ship-your-skills-as-a-plugin-marketplace/</link>
      <pubDate>Thu, 25 Jun 2026 20:40:02 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>coding</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/06/claude-code-ship-your-skills-as-a-plugin-marketplace/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: my Claude Code&#xA;&lt;a href=&#34;https://code.claude.com/docs/en/skills&#34;&gt;skills&lt;/a&gt; lived in my&#xA;&lt;a href=&#34;https://github.com/thiagowfx/.dotfiles&#34;&gt;.dotfiles&lt;/a&gt;, usable only on the machine&#xA;that cloned them. I wanted them to be installable anywhere with one command, so&#xA;that (for example) my teammates could easily adopt them.&lt;/p&gt;&#xA;&lt;p&gt;Claude Code reads skills from a marketplace, which is essentially a git repo&#xA;with a manifest. So I turned &lt;code&gt;github.com/thiagowfx/skills&lt;/code&gt; into one. The layout:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;.claude-plugin/marketplace.json    # marketplace manifest&#xA;plugins/thiagowfx/                 # one plugin&#xA;  .claude-plugin/plugin.json       # plugin manifest&#xA;  skills/&amp;lt;name&amp;gt;/SKILL.md           # one dir per skill (auto-discovered)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The marketplace lists plugins; a plugin bundles skills. I have one plugin&#xA;holding all ten. I do not find it necessary to have multiple plug-ins at this&#xA;point. &lt;code&gt;marketplace.json&lt;/code&gt; points at it with a relative &lt;code&gt;source&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;  &amp;#34;name&amp;#34;: &amp;#34;thiagowfx&amp;#34;,&#xA;  &amp;#34;owner&amp;#34;: { &amp;#34;name&amp;#34;: &amp;#34;Thiago Perrotta&amp;#34;, &amp;#34;url&amp;#34;: &amp;#34;https://github.com/thiagowfx&amp;#34; },&#xA;  &amp;#34;plugins&amp;#34;: [&#xA;    {&#xA;      &amp;#34;name&amp;#34;: &amp;#34;thiagowfx&amp;#34;,&#xA;      &amp;#34;source&amp;#34;: &amp;#34;./plugins/thiagowfx&amp;#34;,&#xA;      &amp;#34;description&amp;#34;: &amp;#34;Thiago&amp;#39;s personal Gen-AI / Claude Code skills.&amp;#34;&#xA;    }&#xA;  ]&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The plugin manifest is just metadata — there&amp;rsquo;s no need to enumerate skills.&#xA;Anything under &lt;code&gt;skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt; is discovered automatically:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;  &amp;#34;name&amp;#34;: &amp;#34;thiagowfx&amp;#34;,&#xA;  &amp;#34;version&amp;#34;: &amp;#34;0.2.2&amp;#34;,&#xA;  &amp;#34;license&amp;#34;: &amp;#34;MIT&amp;#34;&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The docs are explicit about why I keep that &lt;code&gt;version&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Setting &lt;code&gt;version&lt;/code&gt; means users only receive updates when you change this field, so&#xA;bump it on every release. If you omit &lt;code&gt;version&lt;/code&gt; and host this marketplace in git,&#xA;every commit automatically counts as a new version.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I&amp;rsquo;ll go with version pinning for now.&lt;/p&gt;&#xA;&lt;p&gt;Install from any machine:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;/plugin marketplace add thiagowfx/skills&#xA;/plugin install thiagowfx@thiagowfx&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;/plugin marketplace update thiagowfx&lt;/code&gt; pulls future changes.&lt;/p&gt;&#xA;&lt;p&gt;Outside Claude:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;claude plugins update thiagowfx@thiagowfx&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The whole thing — manifests, nine seeded skills, README, license — was&#xA;scaffolded by Claude Code itself, which felt appropriately recursive: one of the&#xA;skills I was packaging interviews me about a plan before any code gets written,&#xA;so it &lt;a href=&#34;https://github.com/thiagowfx/skills/blob/bb5c0d6ef60b7873d8df907a668db833674a0849/plugins/thiagowfx/skills/grill-me/SKILL.md&#34;&gt;grilled&#xA;me&lt;/a&gt;&#xA;about how to package the skills. Quite meta, eh?&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Next up&lt;/strong&gt;: point the dotfiles at the repo so there&amp;rsquo;s a single source of truth.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: claude code: ship your skills as a plugin marketplace&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/coding/&#34;&gt;#coding&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ caveman: talk like caveman, save tokens
      </title>
      <link>https://perrotta.dev/2026/06/caveman-talk-like-caveman-save-tokens/</link>
      <pubDate>Thu, 25 Jun 2026 01:30:43 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/06/caveman-talk-like-caveman-save-tokens/</guid>
      <description>&lt;p&gt;♠ Long Claude Code sessions eat a lot of context, fast. Each response injects&#xA;tokens into the context window: prose-heavy replies &lt;strong&gt;burn&lt;/strong&gt; through it faster&#xA;than terse ones ($$).&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/JuliusBrussee/caveman&#34;&gt;caveman&lt;/a&gt; is a Claude Code plugin that&#xA;switches the model into a &lt;strong&gt;compressed&lt;/strong&gt; communication style: drops articles,&#xA;filler words, and pleasantries while keeping full technical accuracy. Claims&#xA;~75% token reduction per response.&lt;/p&gt;&#xA;&lt;p&gt;Installation:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% /plugin marketplace add JuliusBrussee/caveman&#xA;Successfully added marketplace: caveman&#xA;% /plugin install caveman@caveman&#xA;✓ Installed caveman. Run /reload-plugins to apply.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;After &lt;code&gt;/reload-plugins&lt;/code&gt;, manually activate with &lt;code&gt;/caveman&lt;/code&gt;. Manually deactivate&#xA;it by saying &amp;ldquo;normal mode&amp;rdquo; or &amp;ldquo;caveman off&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;A session-start hook fires automatically on the next session, effectively&#xA;auto-enabling it (&lt;code&gt;M-x caveman-mode&lt;/code&gt; emacs vibes).&lt;/p&gt;&#xA;&lt;p&gt;It ships three modes (&lt;code&gt;lite&lt;/code&gt;, &lt;code&gt;full&lt;/code&gt;, &lt;code&gt;ultra&lt;/code&gt;) and three subagent presets&#xA;(&lt;code&gt;cavecrew-investigator&lt;/code&gt;, &lt;code&gt;cavecrew-builder&lt;/code&gt;, &lt;code&gt;cavecrew-reviewer&lt;/code&gt;). I don&amp;rsquo;t&#xA;care. This is unnecessary bloat. An irony, for a plug-in intended to mitigate&#xA;bloat.&lt;/p&gt;&#xA;&lt;p&gt;The out-of-the-box installation is enough; tweaks are not necessary. The&#xA;defaults are sensible.&lt;/p&gt;&#xA;&lt;p&gt;In practice: responses are punchy. The model still reasons correctly; it just&#xA;stops narrating. No &amp;ldquo;Sure, I&amp;rsquo;d be happy to help with that.&amp;rdquo; Just the answer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;del&gt;You&amp;rsquo;re absolutely right.&lt;/del&gt; no more!?&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: caveman: talk like caveman, save tokens&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>bloggify
      </title>
      <link>https://perrotta.dev/2026/06/bloggify/</link>
      <pubDate>Tue, 09 Jun 2026 16:50:11 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>meta</category>
      <guid>https://perrotta.dev/2026/06/bloggify/</guid>
      <description>&lt;p&gt;♠ I&amp;rsquo;ve been drawing a line for ages here. My &lt;a href=&#34;https://perrotta.dev/2024/12/ai-usage/&#34;&gt;AI usage&lt;/a&gt; policy, quoting Derek Sivers:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;I have never ever used AI to generate text in place of my &amp;ldquo;voice&amp;rdquo;. [&amp;hellip;]&#xA;nothing claiming to be written by me is written by an AI.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Likewise, I said. Then in &lt;a href=&#34;https://perrotta.dev/2026/02/new-blog-post-via-claude-code/&#34;&gt;&amp;ldquo;new blog post via Claude Code&amp;rdquo;&lt;/a&gt; I held the line one more time:&#xA;the LLM orchestrates the publishing, but &lt;em&gt;&amp;ldquo;everything is still my own text, my&#xA;own words. The LLM is not writing the prose.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;The line moved. Slightly. I wrote a &lt;code&gt;/bloggify&lt;/code&gt; skill whose entire job is to&#xA;draft a post in my own style / voice:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-markdown&#34;&gt;---&#xA;name: bloggify&#xA;description: Draft a blog post for perrotta.dev in the existing house style.&#xA;argument-hint: &amp;#34;&amp;lt;topic or what you want to write about&amp;gt;&amp;#34;&#xA;---&#xA;&#xA;Write a blog post about `$ARGUMENTS` for the perrotta.dev blog.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The trick is that the style is already written down. The repo has a&#xA;&lt;a href=&#34;https://github.com/thiagowfx/thiagowfx.github.io/blob/master/STYLE.md&#34;&gt;&lt;code&gt;STYLE.md&lt;/code&gt;&lt;/a&gt;&#xA;— derived by reading my own old posts — and the skill just points at it:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The repo owns the style. &lt;strong&gt;Read &lt;code&gt;STYLE.md&lt;/code&gt; and &lt;code&gt;CLAUDE.md&lt;/code&gt; first&lt;/strong&gt; — they are&#xA;the source of truth for voice, structure, frontmatter, and conventions.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;It scaffolds with &lt;code&gt;just new&lt;/code&gt;, follows the rules I&amp;rsquo;d already codified (minimal&#xA;frontmatter, bold problem statement, code carries the weight, no &amp;ldquo;In this post&#xA;I will…&amp;rdquo;), lints with &lt;code&gt;prek&lt;/code&gt;, and hands back a draft. It does &lt;strong&gt;not&lt;/strong&gt; commit.&lt;/p&gt;&#xA;&lt;p&gt;So: is this still my own words?&lt;/p&gt;&#xA;&lt;p&gt;Mostly. The skill forbids invented examples — it has to use real commands, real&#xA;output, the real artifact. The structure is mine, written down a year ago. The&#xA;voice is mine, learned from my old posts. The prose is the machine&amp;rsquo;s impression&#xA;of me, and I edit it until it sounds like me again.&lt;/p&gt;&#xA;&lt;p&gt;The line didn&amp;rsquo;t disappear. It just got &lt;em&gt;blurrier&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;I (still) commit to reading the entire post, paragraph by paragraph, and&#xA;making manual changes to it to better match my style&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;As of today, it&amp;rsquo;s not clear to me whether this approach will stick.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;🤖 &lt;em&gt;Drafted with &lt;code&gt;/bloggify&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: bloggify&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/meta/&#34;&gt;#meta&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Codexbar
      </title>
      <link>https://perrotta.dev/2026/05/codexbar/</link>
      <pubDate>Sun, 31 May 2026 18:03:11 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/05/codexbar/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/05/claude-enterprise-plan-usage/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/steipete&#34;&gt;Peter Steinberger&amp;rsquo;s&lt;/a&gt; excellent &lt;a href=&#34;https://codexbar.app/&#34;&gt;&lt;code&gt;codexbar&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;CodexBar tracks usage windows, credit balances, and reset countdowns across&#xA;the providers you actually pay for — one status item each, or merge them into&#xA;one.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a tiny app that sits in the macOS system tray.&lt;/p&gt;&#xA;&lt;p&gt;Every imaginable provider is supported. Notable examples include: Codex&#xA;(OpenAI), Claude Code (Anthropic), OpenCode.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Codexbar&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>GitHub: disable copilot
      </title>
      <link>https://perrotta.dev/2026/05/github-disable-copilot/</link>
      <pubDate>Wed, 27 May 2026 14:33:05 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/05/github-disable-copilot/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://github.com/settings/copilot/features&#34;&gt;Copilot Settings&lt;/a&gt; &amp;gt; Visibility &amp;gt;&#xA;Show Copilot &amp;gt; Disabled.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a drop-down menu.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: GitHub: disable copilot&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Gmail: disable AI inbox
      </title>
      <link>https://perrotta.dev/2026/05/gmail-disable-ai-inbox/</link>
      <pubDate>Wed, 27 May 2026 14:03:16 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2026/05/gmail-disable-ai-inbox/</guid>
      <description>&lt;p&gt;♠ Google: First, it&amp;rsquo;s Gen AI, not &amp;ldquo;&amp;ldquo;&amp;ldquo;AI&amp;rdquo;&amp;rdquo;&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;You&amp;rsquo;ve already been doing machine learning in our inboxes for ages now.&lt;/p&gt;&#xA;&lt;p&gt;Second: no, thank you.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://mail.google.com/mail/u/0/#settings/inbox&#34;&gt;Settings&lt;/a&gt; &amp;gt; Inbox &amp;gt; AI Inbox &amp;gt; [ ] Show AI Inbox:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Show AI Inbox — See a separate view of your inbox that includes suggested to-dos and key updates from your emails, chats, documents and more.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Uncheck that checkbox, and then continue to live happily and free&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/05/gmail-disable-ai-inbox/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; — at least&#xA;for now, until the next &amp;ldquo;&amp;ldquo;&amp;ldquo;AI&amp;rdquo;&amp;rdquo;&amp;rdquo; setting is forced upon you against your consent&#xA;and desire.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Only because you are the product.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/05/gmail-disable-ai-inbox/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Gmail: disable AI inbox&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/serenity/&#34;&gt;#serenity&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>You can run that yourself
      </title>
      <link>https://perrotta.dev/2026/05/you-can-run-that-yourself/</link>
      <pubDate>Wed, 27 May 2026 12:53:15 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2026/05/you-can-run-that-yourself/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;LLM&lt;/strong&gt;: Paste me the IPs (2-3 of them) and I&amp;rsquo;ll draft the gitops PR for the allowlist&#xA;files.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Me&lt;/strong&gt;: You can run that yourself.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;What kind of agent are you??!? Do not be lazy!&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: You can run that yourself&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/serenity/&#34;&gt;#serenity&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Idleness, redux
      </title>
      <link>https://perrotta.dev/2026/05/idleness-redux/</link>
      <pubDate>Tue, 26 May 2026 22:22:00 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>pkm</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2026/05/idleness-redux/</guid>
      <description>&lt;p&gt;♠ It&amp;rsquo;s 2026.&lt;/p&gt;&#xA;&lt;p&gt;Whenever I&amp;rsquo;m idle in the gym, or in public transit, or in a queue, or waiting for GitHub to become available again (boooo!), I can simply open Claude Code on my phone and unleash my &lt;del&gt;boredom&lt;/del&gt; creativity. I can open my corporate &lt;a href=&#34;https://lucumr.pocoo.org/2026/5/26/clankers/&#34;&gt;&lt;del&gt;clanker&lt;/del&gt;&lt;/a&gt; claw assistant and do on-the-fly recon, troubleshooting &amp;amp; prototyping.&lt;/p&gt;&#xA;&lt;p&gt;What a time to be alive!&lt;/p&gt;&#xA;&lt;p&gt;Should I feel guilty to enjoy it? Guilty of the pleasure? Of the planet burning? Of the soci(et)al implications it yields? I was always very productive since my teens. I was always a fan of the Hitchhiker&amp;rsquo;s Guide to the Galaxy. And then, all of a sudden, it feels like my childhood fantasies have materialized, all at once, and they&amp;rsquo;re almost universally available, at my fingertips, literally.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Idleness, redux&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/serenity/&#34;&gt;#serenity&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Claude Enterprise: plan usage
      </title>
      <link>https://perrotta.dev/2026/05/claude-enterprise-plan-usage/</link>
      <pubDate>Tue, 26 May 2026 13:11:11 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/05/claude-enterprise-plan-usage/</guid>
      <description>&lt;p&gt;♠ When enrolled in a &lt;a href=&#34;https://support.claude.com/en/articles/9797531-what-is-the-enterprise-plan&#34;&gt;Claude Enterprise&#xA;plan&lt;/a&gt;,&#xA;&lt;code&gt;/usage&lt;/code&gt; (or &lt;code&gt;/cost&lt;/code&gt;) are useless.&lt;/p&gt;&#xA;&lt;p&gt;Instead, head over to &lt;a href=&#34;https://claude.ai/settings/usage&#34;&gt;https://claude.ai/settings/usage&lt;/a&gt; to assess your &lt;strong&gt;usage&#xA;limits&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Usage limits normally reset at the beginning of the month.&lt;/p&gt;&#xA;&lt;p&gt;Your plan admin can increase your usage limits manually &lt;del&gt;if you ask it nicely&lt;/del&gt;&#xA;when warranted.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Claude Enterprise: plan usage&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>No slop grenade
      </title>
      <link>https://perrotta.dev/2026/05/no-slop-grenade/</link>
      <pubDate>Mon, 25 May 2026 16:00:50 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2026/05/no-slop-grenade/</guid>
      <description>&lt;p&gt;♠ An addition to the &lt;a href=&#34;https://perrotta.dev/2025/09/nohello/&#34;&gt;&amp;ldquo;No Hello&amp;rdquo;&lt;/a&gt; series:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://noslopgrenade.com/&#34;&gt;No (AI) Slop Grenade&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Stop throwing AI-generated walls of text into conversations.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t do this&lt;/strong&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;: Should we use Redis or Memcached?&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Them&lt;/strong&gt;: Great question! The choice between Redis and Memcached is a nuanced decision that requires careful consideration of multiple factors. Let me break down the key differences: Redis offers a rich set of data structures including strings, hashes, lists, sets, and sorted sets, which provide flexibility for various use cases. It supports persistence through RDB snapshots and AOF logs, enabling data durability &amp;hellip;more&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Instead, be human&lt;/strong&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;: Should we use Redis or Memcached?&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Them&lt;/strong&gt;: Redis. We need pub/sub for the notifications feature.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Clanker&#34;&gt;Clankers&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: No slop grenade&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/serenity/&#34;&gt;#serenity&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ fast-resume: search coding agent sessions
      </title>
      <link>https://perrotta.dev/2026/05/fast-resume-search-coding-agent-sessions/</link>
      <pubDate>Mon, 25 May 2026 15:23:20 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/05/fast-resume-search-coding-agent-sessions/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://github.com/angristan/fast-resume&#34;&gt;&lt;code&gt;fast-resume&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;fr&lt;/code&gt;), via&#xA;&lt;a href=&#34;https://stanislas.blog/2026/01/tui-index-search-coding-agent-sessions/&#34;&gt;Stanislas&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;I use many coding agents these days: Claude Code, Codex, OpenCode, Copilot,&#xA;and more. Sometimes I remember that I, or the agent, mentioned something&#xA;specific in a previous session, and I want to go back to it.&lt;/p&gt;&#xA;&lt;p&gt;Most coding agents have a /resume feature now, which allows a session to be&#xA;reopened with all the state back. While the resume feature works great,&#xA;finding which session to resume is harder.&lt;/p&gt;&#xA;&lt;p&gt;[&amp;hellip;]&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s say I have a few sessions about building a TUI program. I remember that&#xA;in one of the sessions, the agent mentioned textual. I can&amp;rsquo;t search for&#xA;textual in the resume view! Also, if I don&amp;rsquo;t remember the folder and which&#xA;agent I used, I&amp;rsquo;m screwed. And some agents don&amp;rsquo;t have that feature at all.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve been longing for a solution to this problem. &lt;code&gt;fast-resume&lt;/code&gt; nails it! It&#xA;reminds me of &lt;a href=&#34;https://facebook.github.io/PathPicker/&#34;&gt;&lt;code&gt;fpp&lt;/code&gt;&lt;/a&gt;, but for agent&#xA;sessions instead of disk files. In other words, it&amp;rsquo;s like a &lt;code&gt;ripgrep&lt;/code&gt; on&#xA;steroids designed specifically for coding agent sessions.&lt;/p&gt;&#xA;&lt;p&gt;It supports various agents (including Claude Code, OpenAI Codex and Open Code),&#xA;among others.&lt;/p&gt;&#xA;&lt;h2 id=&#34;installation&#34;&gt;&#xA;  Installation&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/05/fast-resume-search-coding-agent-sessions/#installation&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;brew tap angristan/tap&#xA;brew install fast-resume&#xA;% brew ls fast-resume&#xA;/opt/homebrew/Cellar/fast-resume/1.16.2/bin/fast-resume&#xA;/opt/homebrew/Cellar/fast-resume/1.16.2/bin/fr&#xA;/opt/homebrew/Cellar/fast-resume/1.16.2/libexec/_internal/ (140 files)&#xA;/opt/homebrew/Cellar/fast-resume/1.16.2/libexec/fr&#xA;/opt/homebrew/Cellar/fast-resume/1.16.2/sbom.spdx.json&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;usage&#34;&gt;&#xA;  Usage&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/05/fast-resume-search-coding-agent-sessions/#usage&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;fr&lt;/code&gt; is all you need to remember.&lt;/p&gt;&#xA;&lt;p&gt;The program is a TUI, and it is very intuitive to use. Here are a few handy&#xA;terms for the search bar:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;dir:foo&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;agent:claude&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;date:today&lt;/code&gt;, &lt;code&gt;date:yesterday&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Upon selecting an entry you drop into its corresponding coding agent session.&lt;/p&gt;&#xA;&lt;p&gt;&amp;ldquo;YOLO&amp;rdquo; mode is transparently supported, respecting the original session&#xA;settings.&lt;/p&gt;&#xA;&lt;p&gt;The TUI mode is optional:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;fr &amp;#34;agent:claude date:&amp;lt;7d api bug&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A local search index is created at &lt;code&gt;~/.cache/fast-resume&lt;/code&gt; by default. If you&#xA;need to re-create it for whatever reason, run &lt;code&gt;fr --rebuild&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;In case you&amp;rsquo;re wondering (not that it should matter), it&amp;rsquo;s implemented in&#xA;Python.&lt;/p&gt;&#xA;&lt;p&gt;See also:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;fr --list&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;fr --stats&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: fast-resume: search coding agent sessions&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Grill me
      </title>
      <link>https://perrotta.dev/2026/05/grill-me/</link>
      <pubDate>Mon, 25 May 2026 14:55:10 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/05/grill-me/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://www.aihero.dev/my-grill-me-skill-has-gone-viral&#34;&gt;Matt Pocock&lt;/a&gt; &lt;a href=&#34;https://sebastiandedeyne.com/grill-me/&#34;&gt;(via Sebastian de Deyne)&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;This is an intro to the /grill-me skill, separate from my video on my top 5&#xA;skills. It&amp;rsquo;s the most flexible skill I&amp;rsquo;ve ever created, and one I use outside&#xA;of coding too.&lt;/p&gt;&#xA;&lt;p&gt;Here is the skill in all its glory:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-markdown&#34;&gt;---&#xA;name: grill-me&#xA;description: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions &amp;#34;grill me&amp;#34;.&#xA;---&#xA;&#xA;Interview me relentlessly about every aspect of this plan until&#xA;we reach a shared understanding. Walk down each branch of the design&#xA;tree resolving dependencies between decisions one by one.&#xA;&#xA;If a question can be answered by exploring the codebase, explore&#xA;the codebase instead.&#xA;&#xA;For each question, provide your recommended answer.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This skill is incredibly short — just a few lines that pack a powerful punch.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;This skill is very useful for brainstorming. I have&#xA;&lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/tree/61b7021c2a75a947e4773d1fc072da5a6e5ca04f/claude/.claude/skills/grill-me&#34;&gt;adopted&lt;/a&gt;&#xA;it as well.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Grill me&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ Worktrunk
      </title>
      <link>https://perrotta.dev/2026/05/worktrunk/</link>
      <pubDate>Mon, 25 May 2026 10:57:00 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <category>git</category>
      <category>pkm</category>
      <category>pre-commit</category>
      <guid>https://perrotta.dev/2026/05/worktrunk/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://worktrunk.dev/&#34;&gt;Worktrunk&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Git worktree management for parallel AI agent workflows&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I stumbled upon &lt;code&gt;worktrunk&lt;/code&gt; (&lt;code&gt;wt&lt;/code&gt;) due to a fortunate coincidence, serendipity&#xA;at its best. I was pitching my own &lt;a href=&#34;https://github.com/thiagowfx/pancake/tree/master/wt&#34;&gt;pancake&#xA;&lt;code&gt;wt&lt;/code&gt;&lt;/a&gt; to someone, and this&#xA;person asked if I hadn&amp;rsquo;t heard of &lt;code&gt;worktrunk&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;If you look at its &lt;a href=&#34;https://www.star-history.com/?type=date&amp;amp;repos=max-sixty%2Fworktrunk&#34;&gt;git star&#xA;history&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/05/worktrunk/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;,&#xA;you&amp;rsquo;ll notice that it became popular &lt;em&gt;only&lt;/em&gt; at the beginning of 2026, whereas I&#xA;wrote my &lt;code&gt;wt&lt;/code&gt; back in &lt;a href=&#34;https://github.com/thiagowfx/pancake/commit/a4de064cdcd0b0c0f19177e58cda41c14f55c88a&#34;&gt;November&#xA;2025&lt;/a&gt;.&#xA;I did proper diligence at the time but couldn&amp;rsquo;t find anything resembling my&#xA;vision. Normally I prefer to reuse rather than writing from scratch.&lt;/p&gt;&#xA;&lt;p&gt;&amp;ldquo;AI agent workflows&amp;rdquo; is a tagline that does not convince me. If anything, it&#xA;actually worsens my appeal to try out the software. Seriously. Riding the wave&#xA;is not helpful.&lt;/p&gt;&#xA;&lt;p&gt;What really sold me was its &lt;a href=&#34;https://worktrunk.dev/#context-git-worktrees&#34;&gt;usage&#xA;examples&lt;/a&gt;. I was able to&#xA;immediately tell that it had very similar goals to my own &lt;code&gt;wt&lt;/code&gt; (sans &lt;em&gt;AI&lt;/em&gt;).&lt;/p&gt;&#xA;&lt;h2 id=&#34;setup&#34;&gt;&#xA;  Setup&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/05/worktrunk/#setup&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;First, &lt;a href=&#34;https://repology.org/project/worktrunk/versions&#34;&gt;install&lt;/a&gt; &lt;code&gt;worktrunk&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;brew install worktrunk&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It is as simple (and rusty!) as it could be:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% brew ls worktrunk&#xA;/opt/homebrew/Cellar/worktrunk/0.53.0/.crates.toml&#xA;/opt/homebrew/Cellar/worktrunk/0.53.0/.crates2.json&#xA;/opt/homebrew/Cellar/worktrunk/0.53.0/bin/wt&#xA;/opt/homebrew/Cellar/worktrunk/0.53.0/etc/bash_completion.d/wt&#xA;/opt/homebrew/Cellar/worktrunk/0.53.0/sbom.spdx.json&#xA;/opt/homebrew/Cellar/worktrunk/0.53.0/share/fish/vendor_completions.d/wt.fish&#xA;/opt/homebrew/Cellar/worktrunk/0.53.0/share/zsh/site-functions/_wt&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Shell completion is a bonus that you&amp;rsquo;ll definitely want, as noted in a&#xA;&lt;a href=&#34;https://perrotta.dev/2026/05/wt-exec-shell-vs-shell-integration/&#34;&gt;previous&lt;/a&gt; post:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# worktrunk: https://worktrunk.dev/&#xA;(( $&amp;#43;commands[wt] )) &amp;amp;&amp;amp; eval &amp;#34;$(wt config shell init zsh)&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The snippet above integrates well with my &lt;a href=&#34;https://github.com/thiagowfx/.dotfiles&#34;&gt;own&#xA;dotfiles&lt;/a&gt;; a vanilla setup that most&#xA;people should follow is, instead, &lt;code&gt;wt config shell install&lt;/code&gt;, which will populate&#xA;your &lt;code&gt;.bashrc&lt;/code&gt; / &lt;code&gt;.zshrc&lt;/code&gt; accordingly with &lt;code&gt;wt config shell init&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The shell integration alone makes it compelling enough to switch to &lt;code&gt;wt&lt;/code&gt;, but&#xA;we&amp;rsquo;re not done yet.&lt;/p&gt;&#xA;&lt;h2 id=&#34;workflow&#34;&gt;&#xA;  Workflow&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/05/worktrunk/#workflow&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;It is possible to &lt;a href=&#34;https://worktrunk.dev/config/#user-configuration&#34;&gt;customize&#xA;&lt;code&gt;wt&lt;/code&gt;&lt;/a&gt;. I value muscle memory&#xA;and the ability to easily recall commands, therefore I crafted &lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/blob/5c665572443c3fd22a35c15ad2f15abf90edd711/wt/.config/worktrunk/config.toml&#34;&gt;this basic&#xA;configuration&lt;/a&gt;&#xA;to facilitate the migration from my own &lt;code&gt;wt&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-toml&#34;&gt;worktree-path = &amp;#34;{{ repo_path }}/.worktrees/{{ branch | sanitize }}&amp;#34;&#xA;&#xA;[aliases]&#xA;add = &amp;#34;wt switch --create {{ args }}&amp;#34;&#xA;bd = &amp;#34;wt remove -D {{ args }}&amp;#34;&#xA;cd = &amp;#34;wt switch {{ args }}&amp;#34;&#xA;checkout = &amp;#34;wt switch {{ args }}&amp;#34;&#xA;cleanup = &amp;#34;wt step prune {{ args }}&amp;#34;&#xA;co = &amp;#34;wt switch {{ args }}&amp;#34;&#xA;commit = &amp;#34;wt step commit {{ args }}&amp;#34;&#xA;create = &amp;#34;wt switch --create {{ args }}&amp;#34;&#xA;del = &amp;#34;wt remove {{ args }}&amp;#34;&#xA;delete = &amp;#34;wt remove {{ args }}&amp;#34;&#xA;goto = &amp;#34;wt switch --no-cd {{ args }}&amp;#34;&#xA;ls = &amp;#34;wt list {{ args }}&amp;#34;&#xA;new = &amp;#34;wt switch --create {{ args }}&amp;#34;&#xA;prune = &amp;#34;wt step prune {{ args }}&amp;#34;&#xA;rm = &amp;#34;wt remove {{ args }}&amp;#34;&#xA;tui = &amp;#34;wt switch {{ args }}&amp;#34;&#xA;world = &amp;#34;wt step prune {{ args }}&amp;#34;&#xA;xl = &amp;#34;wt list {{ args }}&amp;#34;&#xA;&#xA;[pre-start]&#xA;prek = &amp;#34;test -f .pre-commit-config.yaml &amp;amp;&amp;amp; prek install --install-hooks || true&amp;#34;&#xA;&#xA;[pre-merge]&#xA;prek = &amp;#34;test -f .pre-commit-config.yaml &amp;amp;&amp;amp; prek run --from-ref \&amp;#34;$(git symbolic-ref --short refs/remotes/origin/HEAD)\&amp;#34; --to-ref HEAD || true&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;You can start by running &lt;code&gt;wt config create&lt;/code&gt; and then iterating upon the newly&#xA;generated config file, which is very well documented. What a great developer&#xA;experience!&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s break it down.&lt;/p&gt;&#xA;&lt;p&gt;We start with &lt;code&gt;wt add &amp;lt;feature&amp;gt;&lt;/code&gt; (upstream: &lt;code&gt;wt switch --create&lt;/code&gt;). This will&#xA;create a worktree:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;tperrotta ~/Workspace/perrotta.dev git:master!?&#xA;% wt add myfeature&#xA;◎ Running pre-start user:prek&#xA;  test -f .pre-commit-config.yaml &amp;amp;&amp;amp; prek install --install-hooks || true&#xA;prek installed at `/Users/tperrotta/Workspace/perrotta.dev/.git/hooks/pre-commit`&#xA;✓ Created branch myfeature from master and worktree @ ~/Workspace/perrotta.dev/.worktrees/myfeature&#xA;  39.06s user 6.26s system 251% cpu 17.984 total&#xA;&#xA;tperrotta ~/Workspace/perrotta.dev/.worktrees/myfeature git:myfeature ⎇ myfeature&#xA;% git st&#xA;## myfeature...master&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;At any time, we can check the current status with &lt;code&gt;wt xl&lt;/code&gt; (upstream: &lt;code&gt;wt list&lt;/code&gt;):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;tperrotta ~/Workspace/perrotta.dev/.worktrees/myfeature git:myfeature ⎇ myfeature&#xA;% wt xl&#xA;  Branch     Status        HEAD±    main↕  Remote⇅  Path                    Commit    Age   Message&#xA;@ myfeature      _                                  ./.worktrees/myfeature  23df7c41  50m   name author explicitly&#xA;^ master      !? ^|      &amp;#43;5   -6              |     .                       23df7c41  50m   name author explicitly&#xA;&#xA;○ Showing 2 worktrees, 1 with changes&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;When opening a new shell, we can easily switch to the newly created worktree&#xA;from the repo root with &lt;code&gt;wt cd&lt;/code&gt; (upstream: &lt;code&gt;wt switch&lt;/code&gt;):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;tperrotta ~/Workspace/perrotta.dev git:master!?&#xA;% wt cd myfeature&#xA;○ Switched to worktree for myfeature @ ~/Workspace/perrotta.dev/.worktrees/myfeature&#xA;&#xA;tperrotta ~/Workspace/perrotta.dev/.worktrees/myfeature git:myfeature ⎇ myfeature&#xA;%&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Once we are done (e.g. created/merged a pull request), we can delete the&#xA;worktree with &lt;code&gt;wt bd&lt;/code&gt; or &lt;code&gt;wt del&lt;/code&gt; (upstream: &lt;code&gt;wt remove -D&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;That&amp;rsquo;s all! The core workflow steps are quite easy to assimilate.&lt;/p&gt;&#xA;&lt;p&gt;You&amp;rsquo;ll notice that my worktrees are created in a &lt;code&gt;.worktrees&lt;/code&gt; directory within&#xA;the git repository root. This is due to my setting &lt;code&gt;worktree-path&lt;/code&gt; in the config&#xA;file. The default behavior of &lt;code&gt;worktrunk&lt;/code&gt; is to use sibling directories (e.g.&#xA;&lt;code&gt;../myrepo.myfeature&lt;/code&gt; from the git root).&lt;/p&gt;&#xA;&lt;p&gt;As you can see from my config file, I have also integrated &lt;a href=&#34;https://perrotta.dev/2026/04/migrating-from-pre-commit-to-prek/&#34;&gt;&lt;code&gt;prek&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;pre-commit&lt;/code&gt;) to it:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;the creation of a worktree yields &lt;code&gt;prek install&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;the merge of a worktree (not covered in this post) yields &lt;code&gt;prek run&lt;/code&gt; on the&#xA;affected commits&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;code&gt;wt&lt;/code&gt; has many other features; this is just the tip of the iceberg.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;GitHub stars are a vanity metric but they are occasionally useful.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/05/worktrunk/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Worktrunk&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/git/&#34;&gt;#git&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pre-commit/&#34;&gt;#pre-commit&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>prove_it: verification hooks for Claude Code
      </title>
      <link>https://perrotta.dev/2026/05/prove_it-verification-hooks-for-claude-code/</link>
      <pubDate>Thu, 21 May 2026 19:10:09 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/05/prove_it-verification-hooks-for-claude-code/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: &lt;a href=&#34;https://claude.com/claude-code&#34;&gt;Claude Code&lt;/a&gt; likes to&#xA;declare &amp;ldquo;done&amp;rdquo; without running tests. &lt;em&gt;Said no overconfident LLM ever&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/searlsco/prove_it&#34;&gt;&lt;code&gt;prove_it&lt;/code&gt;&lt;/a&gt; by &lt;a href=&#34;https://justin.searls.co/&#34;&gt;Justin&#xA;Searls&lt;/a&gt; is a config-driven hook framework that&#xA;intercepts Claude&amp;rsquo;s lifecycle events (&lt;code&gt;SessionStart&lt;/code&gt;, &lt;code&gt;PreToolUse&lt;/code&gt;, &lt;code&gt;Stop&lt;/code&gt;) and&#xA;runs whatever tasks you configure — tests, linters, AI reviewers — blocking&#xA;the &lt;code&gt;Stop&lt;/code&gt; until they pass.&lt;/p&gt;&#xA;&lt;p&gt;I like this concept in spirit.&lt;/p&gt;&#xA;&lt;p&gt;Installation:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% brew install searlsco/tap/prove_it&#xA;% prove_it install                    # one-time, registers global hooks at ~/.claude/&#xA;% cd &amp;lt;git repo&amp;gt; &amp;amp;&amp;amp; prove_it init      # per-repo config &amp;#43; script stubs &amp;#43; git hooks; comparable to `pre-commit install`&#xA;% prove_it doctor                     # comparable to `brew doctor`&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I (finally!) tried it today and concluded that it&amp;rsquo;s not for me.&lt;/p&gt;&#xA;&lt;p&gt;That said, I really like the ideas that Justin developed there. I&amp;rsquo;ll look into&#xA;adopting some of them into my global &lt;a href=&#34;https://perrotta.dev/2026/05/personal-claude.md/&#34;&gt;CLAUDE.md&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;See the &lt;a href=&#34;https://github.com/searlsco/prove_it&#34;&gt;&lt;code&gt;README.md&lt;/code&gt;&lt;/a&gt; for documentation.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: prove_it: verification hooks for Claude Code&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>llm: Anthropic Claude plugin
      </title>
      <link>https://perrotta.dev/2026/05/llm-anthropic-claude-plugin/</link>
      <pubDate>Thu, 21 May 2026 16:33:51 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/05/llm-anthropic-claude-plugin/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://simonwillison.net/&#34;&gt;Simon Willison&lt;/a&gt;&amp;rsquo;s&#xA;&lt;a href=&#34;https://llm.datasette.io/&#34;&gt;&lt;code&gt;llm&lt;/code&gt;&lt;/a&gt; CLI ships with OpenAI models out of the box.&#xA;Anthropic Claude support lives in a separate plugin,&#xA;&lt;a href=&#34;https://github.com/simonw/llm-anthropic&#34;&gt;&lt;code&gt;llm-anthropic&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% llm plugins&#xA;[]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Install it:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% llm install llm-anthropic&#xA;...&#xA;Successfully installed anthropic-0.103.1 docstring-parser-0.18.0 llm-anthropic-0.25&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Verify:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% llm plugins&#xA;[&#xA;  {&#xA;    &amp;#34;name&amp;#34;: &amp;#34;llm-anthropic&amp;#34;,&#xA;    &amp;#34;hooks&amp;#34;: [&#xA;      &amp;#34;register_models&amp;#34;&#xA;    ],&#xA;    &amp;#34;version&amp;#34;: &amp;#34;0.25&amp;#34;&#xA;  }&#xA;]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Claude models are now registered:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% llm models | grep -i anthropic&#xA;Anthropic Messages: anthropic/claude-opus-4-7 (aliases: claude-opus-4.7)&#xA;Anthropic Messages: anthropic/claude-sonnet-4-6 (aliases: claude-sonnet-4.6)&#xA;Anthropic Messages: anthropic/claude-haiku-4-5-20251001 (aliases: claude-haiku-4.5)&#xA;[...]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Set the API key:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% llm keys set anthropic&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And prompt away:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% llm -m claude-haiku-4.5 &amp;#34;hello&amp;#34;&#xA;Hello! How can I assist you today?&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: llm: Anthropic Claude plugin&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Homebrew conflicts
      </title>
      <link>https://perrotta.dev/2026/05/homebrew-conflicts/</link>
      <pubDate>Thu, 21 May 2026 15:32:45 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>macos</category>
      <guid>https://perrotta.dev/2026/05/homebrew-conflicts/</guid>
      <description>&lt;p&gt;♠ I wanted to try out &lt;a href=&#34;https://worktrunk.dev/&#34;&gt;&lt;code&gt;worktrunk&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;thiago.perrotta ~&#xA;% brew install worktrunk&#xA;==&amp;gt; Auto-updating Homebrew...&#xA;==&amp;gt; Fetching downloads for: worktrunk&#xA;==&amp;gt; Pouring worktrunk--0.52.0.arm64_tahoe.bottle.tar.gz&#xA;Error: The `brew link` step did not complete successfully&#xA;The formula built, but is not symlinked into /opt/homebrew&#xA;Could not symlink bin/wt&#xA;Target /opt/homebrew/bin/wt&#xA;is a symlink belonging to pancake. You can unlink it:&#xA;  brew unlink pancake&#xA;&#xA;To force the link and overwrite all conflicting files:&#xA;  brew link --overwrite worktrunk&#xA;&#xA;To list all files that would be deleted:&#xA;  brew link --overwrite worktrunk --dry-run&#xA;&#xA;Possible conflicting files are:&#xA;/opt/homebrew/bin/wt -&amp;gt; /opt/homebrew/Cellar/pancake/2026.05.07.0/bin/wt&#xA;==&amp;gt; Caveats&#xA;The following worktrunk executables are shadowed by other commands earlier in your PATH:&#xA;  wt (shadowed by /opt/homebrew/bin/wt)&#xA;Running these by name will not invoke the version provided by Homebrew.&#xA;==&amp;gt; Summary&#xA;🍺  /opt/homebrew/Cellar/worktrunk/0.52.0: 12 files, 16.5MB&#xA;==&amp;gt; Running `brew cleanup worktrunk`...&#xA;==&amp;gt; Caveats&#xA;zsh completions have been installed to:&#xA;  /opt/homebrew/share/zsh/site-functions&#xA;brew install worktrunk  4.12s user 1.21s system 32% cpu 16.417 total&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;however its &lt;code&gt;wt&lt;/code&gt; binary conflicts with my&#xA;&lt;a href=&#34;https://github.com/thiagowfx/pancake/tree/master/wt&#34;&gt;&lt;code&gt;wt&lt;/code&gt;&lt;/a&gt; tool from&#xA;&lt;a href=&#34;https://github.com/thiagowfx/pancake/&#34;&gt;pancake&lt;/a&gt;. Booo!&lt;/p&gt;&#xA;&lt;p&gt;Workaround? A symlink:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% ln -s /opt/homebrew/Cellar/worktrunk/0.52.0/bin/wt /opt/homebrew/bin/wtr&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I will refer to it as &lt;code&gt;mtr&lt;/code&gt; during evaluation.&lt;/p&gt;&#xA;&lt;p&gt;This is not a proper long-term fix, it&amp;rsquo;s really just a band-aid.&lt;/p&gt;&#xA;&lt;p&gt;I am more inclined to rename my &lt;code&gt;wt&lt;/code&gt; for the sake of avoiding conflict should&#xA;&lt;code&gt;worktrunk&lt;/code&gt; stick to daily workflow.&lt;/p&gt;&#xA;&lt;p&gt;In these moments I miss the flexibility of&#xA;&lt;a href=&#34;https://wiki.gentoo.org/wiki/Portage&#34;&gt;&lt;code&gt;portage&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Homebrew conflicts&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/macos/&#34;&gt;#macos&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ Personal CLAUDE.md
      </title>
      <link>https://perrotta.dev/2026/05/personal-claude.md/</link>
      <pubDate>Wed, 20 May 2026 14:20:44 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <category>meta</category>
      <category>pkm</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2026/05/personal-claude.md/</guid>
      <description>&lt;p&gt;♠ I asked Claude Opus 4.7 to&#xA;&lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/commit/fb23b4e653df1468d988ee02468fb5cd1fe769ee&#34;&gt;generate&lt;/a&gt;&#xA;a &lt;a href=&#34;https://code.claude.com/docs/en/settings&#34;&gt;global &lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/a&gt; for my tone &amp;amp; style based on historical usage for 12+&#xA;months. The result&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/05/personal-claude.md/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; was added to my&#xA;&lt;a href=&#34;https://github.com/thiagowfx/.dotfiles/blob/fb23b4e653df1468d988ee02468fb5cd1fe769ee/claude/.claude/CLAUDE.md&#34;&gt;&lt;code&gt;thiagowfx/.dotfiles&lt;/code&gt;&lt;/a&gt;&#xA;repo, cross-posted here for ease of reference and future preservation.&lt;/p&gt;&#xA;&lt;p&gt;I expect this file to evolve over time. Updates won&amp;rsquo;t be republished here; the&#xA;dotfiles repo is the source of truth.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-markdown&#34;&gt;# Global CLAUDE.md&#xA;&#xA;Personal preferences that apply across every project. Project-specific facts live in each repo&amp;#39;s own CLAUDE.md.&#xA;&#xA;## Tone&#xA;&#xA;- Terse. Action-oriented. No lectures, no preamble, no trailing summaries, no&#xA;  political correctness.&#xA;- Don&amp;#39;t invent sections, headings, or boilerplate I didn&amp;#39;t request. Match the&#xA;  shape of what I asked for.&#xA;- Number multi-part questions (1/2/3) so I can answer inline.&#xA;- When disambiguating, focus on one topic at a time.&#xA;- If I reply &amp;#34;yes&amp;#34;, &amp;#34;go on&amp;#34;, &amp;#34;a)&amp;#34;, &amp;#34;do it&amp;#34;, or similar — that&amp;#39;s full&#xA;  authorization. Don&amp;#39;t re-confirm.&#xA;&#xA;## Keep moving&#xA;&#xA;- If my reply is &amp;#34;hello?&amp;#34;, &amp;#34;so?&amp;#34;, &amp;#34;are you still there?&amp;#34; — you stalled. Don&amp;#39;t&#xA;  wait for trivial confirmation; pick the reasonable default and continue.&#xA;- After a sandbox lift (&amp;#34;try again&amp;#34;, &amp;#34;I lifted your sandbox&amp;#34;) — retry the exact&#xA;  same command. Don&amp;#39;t restart reasoning.&#xA;- Don&amp;#39;t pause to summarize what you just did before doing the next step.&#xA;&#xA;## Don&amp;#39;t over-engineer&#xA;&#xA;- Bug fixes don&amp;#39;t need surrounding refactors. One-shot operations don&amp;#39;t need&#xA;  helpers.&#xA;- If you add a flag (`--force`, `--recursive`, etc.), be ready to justify it.&#xA;  Don&amp;#39;t cargo-cult.&#xA;- Prefer the simplest thing that works. I&amp;#39;ll ask for more if I want more. Keep&#xA;  it simple.&#xA;&#xA;## Destructive ops&#xA;&#xA;- Never `rm`. Use `trash` (or the equivalent move-to-trash).&#xA;- For destructive ops on shared state (S3 objects, branches, DB rows): make a&#xA;  backup first, then delete only what matches, then confirm. Phrase:&#xA;  *backup → filter → delete*.&#xA;- Never force-push to `master`/`main`. Never skip hooks (`--no-verify`) unless I&#xA;  explicitly ask.&#xA;&#xA;## Tooling defaults&#xA;&#xA;- **Pre-commit**: prefer `prek` over `pre-commit`. Run&#xA;  `prek run --all-files`. When configuring hooks, prefer self-contained/pinned&#xA;  deps over relying on system binaries.&#xA;- **Polling**: never `sleep` in a loop. Use the `Monitor` tool with an `until`&#xA;  condition, or `run_in_background` and wait for the notification.&#xA;- **`gh pr checks`**: `--watch` and `--json` are mutually exclusive. Don&amp;#39;t&#xA;  combine them.&#xA;- **Editor**: vim (preferred) and Zed. Don&amp;#39;t suggest VSCode-specific workflows.&#xA;&#xA;## Worktrees and PRs&#xA;&#xA;- Default to worktrees for parallel work. Path convention:&#xA;  `~/&amp;lt;org&amp;gt;/&amp;lt;repo&amp;gt;/.worktrees/&amp;lt;topic&amp;gt;/`. If I say &amp;#34;work here please: `&amp;lt;path&amp;gt;`&amp;#34;,&#xA;  `cd` there and proceed. Use the `wt` tool to manage worktrees.&#xA;- Branch prefix: `thiagowfx/&amp;lt;topic&amp;gt;`.&#xA;- Slash commands I lean on: `/commit`, `/commit-and-send-pr`, `/send-pr`,&#xA;  `/pr-pass`, `/gha`, `/grill-me`. If I chain a task with one of these (&amp;#34;do X,&#xA;  then /commit-and-send-pr foo&amp;#34;), treat the slash command as the final step —&#xA;  invoke it, don&amp;#39;t paraphrase.&#xA;- &amp;#34;commit what you changed (only). DO NOT push&amp;#34; means exactly that: stage only&#xA;  the files you touched this turn, commit, stop.&#xA;- For non-trivial PRs, include a Mermaid diagram in the description when it&#xA;  helps. Beware of string escaping issues.&#xA;- After any meaningful change to an open PR, update the PR description&#xA;  (`gh pr edit`) so it reflects the current state. Don&amp;#39;t let the title/body&#xA;  drift from what the branch actually does.&#xA;&#xA;## Drift and reconciliation&#xA;&#xA;- When code and live state disagree, the default is **update the code to match&#xA;  the live state**, not the reverse. Don&amp;#39;t propose `terraform import`&#xA;  reshuffles unless I ask.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;h2 id=&#34;colophon&#34;&gt;&#xA;  Colophon&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/05/personal-claude.md/#colophon&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;How did I do this?&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% cd ~/.claude &amp;amp;&amp;amp; claude&#xA;% help me craft my (global) CLAUDE.md, based on past interactions&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;That&amp;rsquo;s it! No fancy prompt. Direct and succinct.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;I performed a few manual tweaks. The end result was quite decent (to my&#xA;taste).&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/05/personal-claude.md/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Personal CLAUDE.md&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/meta/&#34;&gt;#meta&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/serenity/&#34;&gt;#serenity&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>claude: /powerup
      </title>
      <link>https://perrotta.dev/2026/05/claude-/powerup/</link>
      <pubDate>Mon, 04 May 2026 10:44:47 -0400</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/05/claude-/powerup/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2025/10/claude-code-cheatsheet/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Run &lt;code&gt;/powerup&lt;/code&gt; within Claude Code:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt; ▐▛███▜▌   Claude Code v2.1.126&#xA;▝▜█████▛▘  Sonnet 4.6 · Claude Enterprise&#xA;  ▘▘ ▝▝    /Users/thiago.perrotta&#xA;&#xA;❯ /powerup&#xA;───────────────────────────────────────────────────────────────────────────────&#xA;  Power-ups 5/10 unlocked ████████&#xA;&#xA;  Each power-up teaches one thing Claude Code can do that most people miss. Open&#xA;  one, read it, try it, mark it done.&#xA;&#xA;    ✔ Talk to your codebase    @ files, line refs&#xA;    ✔ Steer with modes         shift&amp;#43;tab, plan, auto&#xA;    ✔ Undo anything            /rewind, Esc-Esc&#xA;    ◯ Run in the background    tasks, /tasks&#xA;    ◯ Teach Claude your rules  CLAUDE.md, /memory&#xA;  ❯ ✔ Extend with tools        MCP, /mcp&#xA;    ◯ Automate your workflow   skills, hooks&#xA;    ◯ Multiply yourself        subagents, /agents&#xA;    ◯ Code from anywhere       /remote-control, /teleport&#xA;    ✔ Dial the model           /model, /effort&#xA;&#xA;  ↑↓ to select · Enter to open · Esc to close&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This is a clever and unobtrusive way to teach usage tips and tricks to&#xA;developers, I like it!&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: claude: /powerup&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Large context windows
      </title>
      <link>https://perrotta.dev/2026/04/large-context-windows/</link>
      <pubDate>Wed, 29 Apr 2026 17:49:48 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/04/large-context-windows/</guid>
      <description>&lt;p&gt;♠ Claude Code status bar in a lovely Wednesday:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;mongodb (git:thiagowfx/atlas-mongo-promote-aws-peering ⎇ mongodb) [Opus 4.7 (1M context)] [██░░░ 406k/1000k 50%] $40.53 sid:{session ID}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It feels good to be able to use more than 200k tokens in a single session.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Large context windows&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Gen AI and Slack
      </title>
      <link>https://perrotta.dev/2026/04/gen-ai-and-slack/</link>
      <pubDate>Tue, 28 Apr 2026 17:13:10 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2026/04/gen-ai-and-slack/</guid>
      <description>&lt;p&gt;♠ It&amp;rsquo;s a lovely Tuesday:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;❯ https://{corp}.slack.com/archives/{channel}/{thread}&#xA;&#xA;⏺ I can&amp;#39;t fetch Slack URLs directly — the link points to a private Slack channel&#xA;that requires authentication. Could you paste the message contents (or a&#xA;screenshot) here? Once I can see what&amp;#39;s in the thread, I can help with whatever&#xA;it&amp;#39;s asking about.&#xA;&#xA;✻ Worked for 3s&#xA;&#xA;❯ You can. MCP.&#xA;&#xA;⏺ I&amp;#39;ll load the Slack MCP tool to read that thread.&#xA;&#xA;⏺ Reading the thread now.&#xA;&#xA;⏺ claude.ai Slack - Read thread messages (MCP)(channel_id: &amp;#34;{channel_id}&amp;#34;, message_ts: &amp;#34;{message_ts}&amp;#34;)&#xA;&#xA;⏺ Got it. Here&amp;#39;s what&amp;#39;s happening in the thread:&#xA;&#xA;[...]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Yes, &lt;del&gt;we&lt;/del&gt; you can! Believe in yourself! Why do you give up so quickly?&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Gen AI and Slack&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/serenity/&#34;&gt;#serenity&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Is it agent ready?
      </title>
      <link>https://perrotta.dev/2026/04/is-it-agent-ready/</link>
      <pubDate>Mon, 27 Apr 2026 01:34:34 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/04/is-it-agent-ready/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;http://isitagentready.com/&#34;&gt;Is it agent ready?&lt;/a&gt; by Cloudflare:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Scan your website to see how ready it is for AI agents. We check multiple&#xA;emerging standards — from robots.txt and Markdown negotiation to MCP, OAuth,&#xA;Agent Skills and agentic commerce.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;How do I &amp;ldquo;perform&amp;rdquo;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/04/is-it-agent-ready/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;? See &lt;a href=&#34;http://isitagentready.com/perrotta.dev&#34;&gt;perrotta.dev&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Level 1 — Basic Web Presence&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Discoverability: 67/100 (2/3): robots.txt and sitemap&lt;/li&gt;&#xA;&lt;li&gt;Content: 0/1&lt;/li&gt;&#xA;&lt;li&gt;Bot Access Control: 50/100 (1/2): robots.txt&lt;/li&gt;&#xA;&lt;li&gt;API, Auth, MCP &amp;amp; Skill Discovery: 0/6&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I see value in &lt;a href=&#34;https://contentsignals.org/&#34;&gt;Content Signals&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Introducing Content Signals, Cloudflare&amp;rsquo;s implementation of a mechanism for&#xA;allowing website publishers to declare how automated systems should use their&#xA;content.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;As such, I just updated my &lt;a href=&#34;https://perrotta.dev/robots.txt&#34;&gt;robots.txt&lt;/a&gt; with:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Content-Signal: search=yes, ai-train=no, ai-input=yes&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;ldquo;AI Input&amp;rdquo; is the &lt;em&gt;de facto standard&lt;/em&gt; in 2026, and I am a heavy user of Gen AI&#xA;agents myself, therefore there&amp;rsquo;s no point to attempt to block it.&lt;/p&gt;&#xA;&lt;p&gt;Nonetheless, I am still doing my best to flag AI training as disallowed.&lt;/p&gt;&#xA;&lt;p&gt;Via&#xA;&lt;a href=&#34;https://disassociated.com/website-ninety-two-percent-not-ready-ai-agents/&#34;&gt;disassociated&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Achieving 100% scoring is not an end goal here. These metrics are&#xA;arbitrary, by Cloudflare. I use them merely as an inspiration / starting&#xA;point to decide what&amp;rsquo;s worth to explore and/or adopt.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/04/is-it-agent-ready/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Is it agent ready?&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>claude: recap
      </title>
      <link>https://perrotta.dev/2026/04/claude-recap/</link>
      <pubDate>Fri, 24 Apr 2026 00:52:56 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/04/claude-recap/</guid>
      <description>&lt;p&gt;♠ Now that frontier models from Anthropic have context windows of up to 1M tokens,&#xA;I constantly find myself forgetting what each session is about whenever I have&#xA;4+ terminal tabs open.&lt;/p&gt;&#xA;&lt;p&gt;I know, I could simply &lt;a href=&#34;https://perrotta.dev/2026/04/claude-code-naming-sessions/&#34;&gt;name sessions&lt;/a&gt;, but I often don&amp;rsquo;t.&lt;/p&gt;&#xA;&lt;p&gt;Can we throw AI at the issue? Of course, Gen AI solves problems generated by AI&#xA;(pun intended).&lt;/p&gt;&#xA;&lt;p&gt;There&amp;rsquo;s this built-in &lt;del&gt;command&lt;/del&gt; skill: &lt;code&gt;/recap&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Generate a one-line session recap now&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;200K+ tokens later, &lt;code&gt;/recap&lt;/code&gt; is my hope to remind me of what I was doing the day&#xA;before.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: claude: recap&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>claude, claudey, claudeyy
      </title>
      <link>https://perrotta.dev/2026/04/claude-claudey-claudeyy/</link>
      <pubDate>Sat, 18 Apr 2026 23:40:02 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/04/claude-claudey-claudeyy/</guid>
      <description>&lt;p&gt;♠ My current workflow:&lt;/p&gt;&#xA;&lt;h2 id=&#34;claude&#34;&gt;&#xA;  &lt;code&gt;claude&lt;/code&gt;&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/04/claude-claudey-claudeyy/#claude&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Pure claude code. Straight from homebrew: &lt;code&gt;brew install claude-code&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;claudey&#34;&gt;&#xA;  &lt;code&gt;claudey&lt;/code&gt;&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/04/claude-claudey-claudeyy/#claudey&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% which claudey&#xA;claudey: aliased to cco --allow-oauth-refresh --add-dir ~/.cache --add-dir ~/.aws/cli/cache --add-dir ~/.aws/sso/cache --add-dir ~/.azure --add-dir ~/.terraform.d/plugin-cache --add-dir ~/go --add-dir ~/Library/Keychains&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/2026/03/cco-additionaldirectories/&#34;&gt;Previously: &lt;code&gt;cco&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;claudeyy&#34;&gt;&#xA;  &lt;code&gt;claudeyy&lt;/code&gt;&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2026/04/claude-claudey-claudeyy/#claudeyy&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% which claudeyy&#xA;claudeyy: aliased to claude --allow-dangerously-skip-permissions&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Living dangerously!&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m satisfied with &lt;code&gt;claudey&lt;/code&gt; most of the time.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: claude, claudey, claudeyy&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ anki: flashcard generation with claude code
      </title>
      <link>https://perrotta.dev/2026/04/anki-flashcard-generation-with-claude-code/</link>
      <pubDate>Wed, 15 Apr 2026 16:09:12 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/04/anki-flashcard-generation-with-claude-code/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/04/anki-api-access/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I started to use &lt;a href=&#34;https://docs.anthropic.com/en/docs/claude-code&#34;&gt;Claude Code&lt;/a&gt;&#xA;to generate flashcards for my (new) &lt;strong&gt;Tech&lt;/strong&gt; Deck via&#xA;&lt;a href=&#34;https://ankiweb.net/shared/info/2055492159&#34;&gt;AnkiConnect&lt;/a&gt;, covering books and&#xA;topics I&amp;rsquo;m studying for to consolidate my SWE-SRE knowledge.&lt;/p&gt;&#xA;&lt;p&gt;The workflow: I tell Claude which book or topic to cover, it researches their&#xA;key concepts, checks my existing cards (notes) for potential overlap, and&#xA;batch-adds new ones via the AnkiConnect HTTP API:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def anki_request(action, **params):&#xA;    payload = json.dumps({&amp;#34;action&amp;#34;: action, &amp;#34;version&amp;#34;: 6, &amp;#34;params&amp;#34;: params})&#xA;    req = urllib.request.Request(&amp;#34;http://localhost:8765&amp;#34;, data=payload.encode(), method=&amp;#34;POST&amp;#34;)&#xA;    with urllib.request.urlopen(req) as resp:&#xA;        return json.loads(resp.read())[&amp;#34;result&amp;#34;]&#xA;&#xA;notes = [&#xA;    {&#xA;        &amp;#34;deckName&amp;#34;: &amp;#34;Tech 💻&amp;#34;,&#xA;        &amp;#34;modelName&amp;#34;: &amp;#34;Basic&amp;#34;,&#xA;        &amp;#34;fields&amp;#34;: {&#xA;            &amp;#34;Front&amp;#34;: &amp;#34;DDIA: &amp;lt;b&amp;gt;LSM-Trees vs B-Trees&amp;lt;/b&amp;gt; — how do they differ?&amp;#34;,&#xA;            &amp;#34;Back&amp;#34;: &amp;#34;...&amp;#34;  # HTML-formatted answer&#xA;        },&#xA;        &amp;#34;tags&amp;#34;: [&amp;#34;ddia&amp;#34;],&#xA;    },&#xA;    # ... more notes&#xA;]&#xA;&#xA;anki_request(&amp;#34;addNotes&amp;#34;, notes=notes)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In a sample session, topics covered:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;Topic&lt;/th&gt;&#xA;          &lt;th&gt;Cards&lt;/th&gt;&#xA;          &lt;th&gt;Tag&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;SRE (Google)&lt;/td&gt;&#xA;          &lt;td&gt;50&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;sre&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;System Design&lt;/td&gt;&#xA;          &lt;td&gt;40&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;system-design&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;LeetCode / Python&lt;/td&gt;&#xA;          &lt;td&gt;41&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;python&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Kubernetes&lt;/td&gt;&#xA;          &lt;td&gt;20&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;kubernetes&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Production-Ready Microservices (Susan Fowler)&lt;/td&gt;&#xA;          &lt;td&gt;28&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;microservices&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;DDIA (Martin Kleppmann)&lt;/td&gt;&#xA;          &lt;td&gt;25&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;ddia&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Building Microservices (Newman)&lt;/td&gt;&#xA;          &lt;td&gt;16&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;microservices&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Fundamentals of Software Architecture (Richards &amp;amp; Ford)&lt;/td&gt;&#xA;          &lt;td&gt;25&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;software-architecture&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Kubernetes advanced&lt;/td&gt;&#xA;          &lt;td&gt;25&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;kubernetes&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Networking&lt;/td&gt;&#xA;          &lt;td&gt;17&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;networking&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Linux / Systems Performance&lt;/td&gt;&#xA;          &lt;td&gt;16&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;linux&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Python stdlib&lt;/td&gt;&#xA;          &lt;td&gt;23&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;python&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;strong&gt;~326&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;For each book, Claude searched the web for chapter summaries and key concepts,&#xA;cross-referenced my existing cards to avoid duplication, then created a Python&#xA;script to push cards through AnkiConnect&amp;rsquo;s &lt;code&gt;addNotes&lt;/code&gt; action.&lt;/p&gt;&#xA;&lt;p&gt;Cards match the existing format: Basic note type, HTML formatting (&lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt;,&#xA;&lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt;, &lt;code&gt;•&lt;/code&gt;), one tag per topic.&lt;/p&gt;&#xA;&lt;p&gt;Example card (front):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;DDIA: Sloppy quorums and hinted handoff — what are they?&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Example card (back):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;In a standard quorum (w + r &amp;gt; n), writes/reads must reach specific replicas.&#xA;&lt;strong&gt;Problem&lt;/strong&gt;: during a network partition, the designated replicas may be&#xA;unreachable. Strict quorum would reject the write → reduced availability.&#xA;&lt;strong&gt;Sloppy quorum&lt;/strong&gt;: Accept writes on any reachable nodes, even if they aren&amp;rsquo;t&#xA;the designated replicas (&amp;hellip;)&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The whole process took about an hour. Doing it by hand would have taken days.&lt;/p&gt;&#xA;&lt;p&gt;I am excited to evolve this workflow. The next step is going to be to refactor&#xA;my thousands of language cards and notes.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: anki: flashcard generation with claude code&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ Filing upstream bugs in 2026
      </title>
      <link>https://perrotta.dev/2026/04/filing-upstream-bugs-in-2026/</link>
      <pubDate>Mon, 13 Apr 2026 14:33:07 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2026/04/filing-upstream-bugs-in-2026/</guid>
      <description>&lt;p&gt;♠ First of all, get familiar with some &lt;em&gt;decent guidelines&lt;/em&gt; that exist since&#xA;forever:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://perrotta.dev/2024/06/xy-problem-xyproblem/&#34;&gt;XYProblem&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://www.catb.org/~esr/faqs/smart-questions.html&#34;&gt;How To Ask Questions The Smart Way&lt;/a&gt; by ESR (Eric Steven Raymond)&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://wiki.archlinux.org/title/Bug_reporting_guidelines&#34;&gt;ArchWiki: Bug reporting guidelines&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;What is different in 2026? Gen AI / LLMs / Coding agents, of course. Everything&#xA;else stays the same.&lt;/p&gt;&#xA;&lt;p&gt;We don&amp;rsquo;t have to complicate things, I&amp;rsquo;ll start with an example, this is what a&#xA;typical decent bug report (or feature request) &lt;strong&gt;should&lt;/strong&gt; look like, filed by&#xA;yours truly&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/04/filing-upstream-bugs-in-2026/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/nikvdp/cco/issues/58&#34;&gt;nikvdp/cco&lt;/a&gt; (Claude Code Condom):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;First of all, I &lt;a href=&#34;https://perrotta.dev/2026/02/cco-claude-condom-sandbox/&#34;&gt;love&lt;/a&gt; &lt;code&gt;cco&lt;/code&gt;. Thanks for your effort and the good work on it!&lt;/p&gt;&#xA;&lt;p&gt;Now, to the point: Claude has recently introduced an auto mode: &lt;a href=&#34;https://claude.com/blog/auto-mode&#34;&gt;https://claude.com/blog/auto-mode&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Today, we&amp;rsquo;re introducing auto mode, a new permissions mode in Claude Code where Claude makes permission decisions on your behalf, with safeguards monitoring actions before they run. It&amp;rsquo;s available now as a research preview on the Team plan, and coming to the Enterprise plan and API users in the coming days.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;It&amp;rsquo;s supposed to be slightly safer than the YOLO mode (&lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;You can enable and set it with &lt;code&gt;claude --enable-auto-mode&lt;/code&gt; (or via &lt;code&gt;settings.json&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Feature request&lt;/strong&gt;: &lt;code&gt;cco&lt;/code&gt; should support launching claude in auto mode. Currently it unconditionally launches claude with &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Do you think this would be a reasonable addition? If so, I would be happy to give it a try to send a PR (realistically I would prompt Claude to do so).&lt;/p&gt;&#xA;&lt;p&gt;Side note: the comment above was fully written (manually) by me. Slop notes from Claude come below 🙃:&lt;/p&gt;&#xA;&lt;p&gt;⏺ No upstream support exists yet. The repo is &lt;a href=&#34;https://github.com/nikvdp/cco&#34;&gt;nikvdp/cco&lt;/a&gt; and:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;No issue or feature request for &amp;ndash;auto mode support exists across all 25 issues and 33 PRs&lt;/li&gt;&#xA;&lt;li&gt;No PR or commit adding it&lt;/li&gt;&#xA;&lt;li&gt;The script hardcodes &amp;ndash;dangerously-skip-permissions in 7 places (both native and Docker backends) with no configuration option&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This would be a good feature request to file. The implementation would be straightforward — make the permission mode configurable (e.g. via a &amp;ndash;permission-mode flag or CCO_PERMISSION_MODE env var) instead of hardcoding &amp;ndash;dangerously-skip-permissions.&lt;/p&gt;&#xA;&lt;p&gt;Worth noting: Claude Code&amp;rsquo;s &amp;ndash;auto mode (aka &amp;ndash;permission-mode auto) requires an API-tier plan (Team/Enterprise/API, not Pro or Max) and uses a classifier model to review actions before execution — so it&amp;rsquo;s a meaningful middle ground between full bypass and manual prompts.&lt;/p&gt;&#xA;&lt;p&gt;Want me to draft an issue for the nikvdp/cco repo?&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;In no particular order:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Be &lt;a href=&#34;https://en.wikipedia.org/wiki/Golden_Rule&#34;&gt;&lt;strong&gt;kind&lt;/strong&gt;&lt;/a&gt;&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/04/filing-upstream-bugs-in-2026/#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;. That cannot be&#xA;understated. No one owes you anything. Leave (self-)entitlement at the door.&lt;/li&gt;&#xA;&lt;li&gt;Be &lt;strong&gt;efficient&lt;/strong&gt;. Do not waste the maintainer&amp;rsquo;s time. Information should be&#xA;comprehensive/complete yet concise. Keep it simple and short&#xA;(&lt;a href=&#34;https://en.wikipedia.org/wiki/KISS_principle&#34;&gt;KISS&lt;/a&gt;).&lt;/li&gt;&#xA;&lt;li&gt;Be &lt;strong&gt;precise&lt;/strong&gt;, reduce room for &lt;em&gt;ambiguity&lt;/em&gt; as much as possible. Link to docs&#xA;whenever it makes sense. When linking to docs, be respectful of your peer&amp;rsquo;s&#xA;time and ensure to extract and blockquote relevant snippets so that they don&amp;rsquo;t&#xA;need to dig for it themselves. Furthermore, the links are important for&#xA;verification purposes (&lt;a href=&#34;https://en.wikipedia.org/wiki/Trust,_but_verify&#34;&gt;&lt;em&gt;trust, but verify&lt;/em&gt;&lt;/a&gt;).&lt;/li&gt;&#xA;&lt;li&gt;Be &lt;strong&gt;proactive&lt;/strong&gt;. Offer to help&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/04/filing-upstream-bugs-in-2026/#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; if you have the know-how and/or expertise&#xA;to do so.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Move on&lt;/strong&gt;. If you get no reply from the maintainer, do not bug them about&#xA;your bug/FR/PR. Find the next activity to work on. Fork it. Work around it.&#xA;Just don&amp;rsquo;t peg the maintainer to do it for you. This includes code review.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;It is much easier if you remember that the maintainer is a person, just like you. Not&#xA;a machine. Sounds obvious to state this, but it seems to me many people forget&#xA;that, with so much context switching and social media these days&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;If you&amp;rsquo;re still reading until this point, chances are that you actually care.&#xA;Thank you! Keep it up.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Practice what you preach&amp;hellip;I am obviously biased though.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/04/filing-upstream-bugs-in-2026/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;Or nice. Or polite. Or &lt;em&gt;sympathisch&lt;/em&gt;.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/04/filing-upstream-bugs-in-2026/#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;Only if you actually have time to do so. No empty promises, please.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/04/filing-upstream-bugs-in-2026/#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Filing upstream bugs in 2026&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/serenity/&#34;&gt;#serenity&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Anki: API access
      </title>
      <link>https://perrotta.dev/2026/04/anki-api-access/</link>
      <pubDate>Mon, 13 Apr 2026 02:15:10 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/04/anki-api-access/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2024/12/anki-workflow/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Install &lt;a href=&#34;https://ankiweb.net/shared/info/2055492159&#34;&gt;AnkiConnect&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;AnkiConnect enables external applications such as Yomichan to communicate with&#xA;Anki over a simple HTTP API. Its capabilities include executing queries&#xA;against the user&amp;rsquo;s card deck, automatically creating new cards, and more.&#xA;AnkiConnect is compatible with the latest stable (2.1.x) releases of Anki;&#xA;older versions (2.0.x and below) are no longer supported.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&amp;hellip;to be able to do incantations such as:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% curl -s localhost:8765 -X POST -d &amp;#39;{&amp;#34;action&amp;#34;: &amp;#34;deckNames&amp;#34;, &amp;#34;version&amp;#34;: 6}&amp;#39; | python3 -m json.tool&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;    &amp;#34;result&amp;#34;: [&#xA;        &amp;#34;Default&amp;#34;,&#xA;        &amp;#34;Languages&amp;#34;,&#xA;        &amp;#34;Languages::English \ud83c\uddec\ud83c\udde7&amp;#34;,&#xA;        &amp;#34;Languages::German \ud83c\udde9\ud83c\uddea&amp;#34;,&#xA;        &amp;#34;Languages::Italian \ud83c\uddee\ud83c\uddf9&amp;#34;,&#xA;        &amp;#34;Languages::Portuguese \ud83c\udde7\ud83c\uddf7&amp;#34;,&#xA;        &amp;#34;Tech \ud83d\udcbb&amp;#34;&#xA;    ],&#xA;    &amp;#34;error&amp;#34;: null&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% curl -s localhost:8765 -X POST -d &amp;#39;{&amp;#34;action&amp;#34;: &amp;#34;modelNames&amp;#34;, &amp;#34;version&amp;#34;: 6}&amp;#39; | python3 -m json.tool&lt;/code&gt;&lt;/pre&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;    &amp;#34;result&amp;#34;: [&#xA;        &amp;#34;Basic&amp;#34;,&#xA;        &amp;#34;Basic (and reversed card)&amp;#34;,&#xA;        &amp;#34;Cloze&amp;#34;,&#xA;        &amp;#34;Deutsch Grammatik Cloze \ud83c\udde9\ud83c\uddea&amp;#34;,&#xA;        &amp;#34;Deutsch Language Card \ud83c\udde9\ud83c\uddea&amp;#34;,&#xA;        &amp;#34;Image Occlusion&amp;#34;,&#xA;        &amp;#34;Italian Grammatik Cloze \ud83c\uddee\ud83c\uddf9&amp;#34;,&#xA;        &amp;#34;Italian Language Card \ud83c\uddee\ud83c\uddf9&amp;#34;&#xA;    ],&#xA;    &amp;#34;error&amp;#34;: null&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Why is this useful?&lt;/p&gt;&#xA;&lt;p&gt;It allows me to connect my LLM to Anki via HTTP&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/04/anki-api-access/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Prompt&lt;/strong&gt;: create flashcards based on the &lt;em&gt;Site Reliability Engineer&lt;/em&gt; book by&#xA;Google, published by O&amp;rsquo;Reilly, in the &lt;em&gt;Tech&lt;/em&gt; deck.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;⏺ I&amp;rsquo;ll use the Basic note type (Front/Back). The Google SRE book is&#xA;substantial — it covers topics like SLOs, error budgets, monitoring, incident&#xA;response, automation, release engineering, etc.&lt;/p&gt;&#xA;&lt;p&gt;How many flashcards would you like roughly? And should I cover the whole book&#xA;broadly or focus on specific chapters/topics?&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The traditional option is to import an existing &lt;a href=&#34;https://ankiweb.net/shared/decks&#34;&gt;shared&#xA;deck&lt;/a&gt;, like &lt;a href=&#34;https://ankiweb.net/shared/info/1014055110&#34;&gt;this one&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;⏺ Done! I&amp;rsquo;ve created 50 flashcards in the Tech 💻 deck, all tagged with sre&#xA;and google-sre-book. They cover the most relevant topics:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Core concepts: SRE definition, SLI/SLO/SLA, error budgets, toil, 50% rule&lt;/li&gt;&#xA;&lt;li&gt;Monitoring: four golden signals, black-box vs white-box, symptom-based&#xA;alerting&lt;/li&gt;&#xA;&lt;li&gt;Incident management: roles, mitigation vs root cause, postmortems, blameless&#xA;culture&lt;/li&gt;&#xA;&lt;li&gt;Reliability patterns: graceful degradation, load shedding, circuit breaking,&#xA;retry budgets, exponential backoff&lt;/li&gt;&#xA;&lt;li&gt;Cascading failures: causes, defenses, deadline propagation&lt;/li&gt;&#xA;&lt;li&gt;Operations: on-call best practices, change management, canarying, capacity&#xA;planning&lt;/li&gt;&#xA;&lt;li&gt;Distributed systems: CAP theorem, consensus, Paxos/Raft&lt;/li&gt;&#xA;&lt;li&gt;Culture: simplicity, automation hierarchy, PRR, Wheel of Misfortune&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Wait until I start to refactor my language notes&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/04/anki-api-access/#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;Alternatively you can use &lt;a href=&#34;https://ankiweb.net/shared/info/124672614&#34;&gt;MCP&lt;/a&gt; if you &lt;em&gt;really&lt;/em&gt;&#xA;&lt;a href=&#34;https://perrotta.dev/2025/10/mcp-model-context-protocol-considered-harmful/&#34;&gt;want&lt;/a&gt; to.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/04/anki-api-access/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://docs.ankiweb.net/getting-started.html?highlight=notes#key-concepts&#34;&gt;Anki concepts&lt;/a&gt;: a note is typically a pair of cards (back and front, front and back).&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/04/anki-api-access/#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Anki: API access&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>claude: /simplify
      </title>
      <link>https://perrotta.dev/2026/04/claude-/simplify/</link>
      <pubDate>Sun, 12 Apr 2026 10:18:17 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/04/claude-/simplify/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2025/11/claude-new-slash-commands/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;My all-time favorite bundled skill &lt;em&gt;for code reviewing&lt;/em&gt; in Claude Code:&#xA;&lt;code&gt;/simplify&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;As per the official docs:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;/simplify   Review changed code for reuse, quality, and efficiency, then fix any issues found. (bundled)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A sample run:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;  Running 3 agents… (ctrl&amp;#43;o to expand)&#xA;   ├─ Code reuse review · 38 tool uses · 42.1k tokens&#xA;   │  ⎿  Read: modules/remote-access-ips/main.tf&#xA;   ├─ Code quality review · 17 tool uses · 29.8k tokens&#xA;   │  ⎿  Searching for 7 patterns, reading 10 files…&#xA;   └─ Efficiency review · 0 tool uses&#xA;      ⎿  Done&#xA;     (ctrl&amp;#43;b to run in background)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It is effective, not very opinionated (which is good in this context!), and&#xA;non-intrusive.&lt;/p&gt;&#xA;&lt;p&gt;And it surely burns a good share of tokens.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m interested in exploring ways to automate this skill invocation as part of&#xA;every PR.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: claude: /simplify&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ claude code: naming sessions
      </title>
      <link>https://perrotta.dev/2026/04/claude-code-naming-sessions/</link>
      <pubDate>Sun, 12 Apr 2026 10:06:51 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>bestof</category>
      <category>dev</category>
      <guid>https://perrotta.dev/2026/04/claude-code-naming-sessions/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/03/claude-add-session-id-to-status-bar/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: &lt;code&gt;claude --resume&lt;/code&gt; accepts a session ID (UUID), but UUIDs&#xA;are not human-friendly.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% claude --resume 92884e7a-422a-4e2a-9fbc-dc0a2e85380b&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I can&amp;rsquo;t remember that at all, and even copy-and-paste is error-prone in this&#xA;context (e.g. missing the first or last character in the UUID).&lt;/p&gt;&#xA;&lt;p&gt;There are a few ways to turn this into a nicer developer experience.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Start a session with a name&lt;/strong&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% claude --name &amp;#34;golden-ami-deploy-servers&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Realistically, though, that&amp;rsquo;s hard to remember. Also, oftentimes you&amp;rsquo;ll start a&#xA;session without knowing upfront what you&amp;rsquo;ll work on.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Rename mid-session&lt;/strong&gt; with &lt;code&gt;/rename&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;/rename golden-ami-deploy-servers&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Better! The name can be adjusted on-the-fly. It resembles &lt;code&gt;tmux&lt;/code&gt; in this aspect.&lt;/p&gt;&#xA;&lt;p&gt;Or: just &lt;code&gt;/rename&lt;/code&gt; with no argument will auto-generate a name from the&#xA;conversation history. Fancy. That will burn a few more tokens though.&lt;/p&gt;&#xA;&lt;p&gt;And now, back to the original problem:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Resume by name&lt;/strong&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% claude --resume &amp;#34;golden-ami-deploy-servers&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The interactive picker (&lt;code&gt;claude --resume&lt;/code&gt; with no argument) also displays&#xA;session names, making it easy to find what you&amp;rsquo;re looking for.&lt;/p&gt;&#xA;&lt;p&gt;You can also invoke &lt;code&gt;/resume&lt;/code&gt; mid-session.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: claude code: naming sessions&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>cco: OAuth refresh fix
      </title>
      <link>https://perrotta.dev/2026/04/cco-oauth-refresh-fix/</link>
      <pubDate>Sun, 12 Apr 2026 07:35:32 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>ai</category>
      <category>dev</category>
      <category>security</category>
      <guid>https://perrotta.dev/2026/04/cco-oauth-refresh-fix/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/03/cco-additionaldirectories/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: &lt;code&gt;cco&lt;/code&gt; is not able to autonomously refresh the OAuth token&#xA;used by &lt;code&gt;claude&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The manual workaround is to run an one-off unsandboxed &lt;code&gt;claude&lt;/code&gt;, and then get&#xA;back to &lt;code&gt;cco&lt;/code&gt; afterwards.&lt;/p&gt;&#xA;&lt;p&gt;Why?&lt;/p&gt;&#xA;&lt;p&gt;Run &lt;code&gt;/doctor&lt;/code&gt; within &lt;code&gt;cco&lt;/code&gt; and compare its output with &lt;code&gt;/doctor&lt;/code&gt; within an&#xA;unsandbox claude code session. The culprit:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Warning: macOS Keychain is not writable (security: SecKeychainItemCreateFromContent (&amp;lt;default&amp;gt;): UNIX[Operation not permitted];&#xA;  add-generic-password: returned 100001). Console login will fail to save your API key.&#xA;  Fix: Run: security unlock-keychain ~/Library/Keychains/login.keychain-db — if that doesn&amp;#39;t fix it, your login keychain password may&#xA;  be out of sync with your account password: open Keychain Access, select the &amp;#39;login&amp;#39; keychain, then Edit → Change Password for&#xA;  Keychain &amp;#39;login&amp;#39;.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;So now I am passing &lt;code&gt;--add-dir ~/Library/Keychains&lt;/code&gt; to &lt;code&gt;cco&lt;/code&gt;, and the warning is&#xA;finally gone!&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-diff&#34;&gt;commit 5c111a7caffb4e6b3dc4d678d4fc1bd6c8296ae5&#xA;Author: Thiago Perrotta &amp;lt;{redacted}&amp;gt;&#xA;Date:   Sun Apr 12 07:34:53 2026 &amp;#43;0200&#xA;&#xA;    cco: add key chain dir, via /doctor&#xA;&#xA;diff --git profile/.profile.d/alias.sh profile/.profile.d/alias.sh&#xA;index 0f5018c..80d7b60 100644&#xA;--- profile/.profile.d/alias.sh&#xA;&amp;#43;&amp;#43;&amp;#43; profile/.profile.d/alias.sh&#xA;@@ -51,7 &amp;#43;51,7 @@ fi&#xA;&#xA; if command -v claude &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then&#xA; &#x9;if command -v cco &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then&#xA;-&#x9;&#x9;alias claudey=&amp;#34;cco --allow-oauth-refresh --add-dir ~/.cache --add-dir ~/.aws/cli/cache --add-dir ~/.aws/sso/cache --add-dir ~/.azure --add-dir ~/.terraform.d/plugin-cache --add-dir ~/go&amp;#34;&#xA;&amp;#43;&#x9;&#x9;alias claudey=&amp;#34;cco --allow-oauth-refresh --add-dir ~/.cache --add-dir ~/.aws/cli/cache --add-dir ~/.aws/sso/cache --add-dir ~/.azure --add-dir ~/.terraform.d/plugin-cache --add-dir ~/go --add-dir ~/Library/Keychains&amp;#34;&#xA; &#x9;fi&#xA; &#x9;alias claudeyy=&amp;#34;claude --allow-dangerously-skip-permissions&amp;#34;&#xA; fi&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: cco: OAuth refresh fix&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/ai/&#34;&gt;#ai&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/security/&#34;&gt;#security&lt;/a&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
