<?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>Pkm on ¬ just serendipity 🍀</title>
    <link>https://perrotta.dev/</link>
    <description>Recent content in Pkm 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/pkm/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>Anki: archive a deck
      </title>
      <link>https://perrotta.dev/2026/07/anki-archive-a-deck/</link>
      <pubDate>Mon, 27 Jul 2026 10:49:00 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/07/anki-archive-a-deck/</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;The &lt;a href=&#34;https://docs.ankiweb.net/&#34;&gt;Anki official docs&lt;/a&gt; do not provide explicit&#xA;instructions about the archival of decks that are no longer needed.&lt;/p&gt;&#xA;&lt;p&gt;Archiving is better than deleting because you never know when you may need a&#xA;deck again.&lt;/p&gt;&#xA;&lt;p&gt;One way to archive a deck is to simply export it as a backup and save it&#xA;elsewhere. But then you collection becomes scattered. I&amp;rsquo;d really like to manage&#xA;all my decks in a &lt;a href=&#34;https://ankiweb.net/about&#34;&gt;single place&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;So I came up with a simple workaround.&lt;/p&gt;&#xA;&lt;p&gt;First, create an &lt;code&gt;Archive::&lt;/code&gt;&#xA;&lt;a href=&#34;https://docs.ankiweb.net/deck-options.html?highlight=subdeck#subdecks&#34;&gt;subdeck&lt;/a&gt;.&#xA;A subdeck creates a parent-child relationship which, for our purposes, bundles&#xA;all archived decks within an umbrella parent. It&amp;rsquo;s visually easier to manage and&#xA;organize, effectively hiding archived decks from the deck list view.&lt;/p&gt;&#xA;&lt;p&gt;Second, move the desired deck(s) within &lt;code&gt;Archive::&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Third, one by one, open the cards/notes list (&amp;ldquo;Browse&amp;rdquo;) of a deck, select all&#xA;cards/notes (&lt;code&gt;Cmd-A&lt;/code&gt;), then&#xA;&lt;a href=&#34;https://docs.ankiweb.net/browsing.html?highlight=suspend#cards&#34;&gt;suspend&lt;/a&gt; them&#xA;all (&lt;code&gt;Cmd-J&lt;/code&gt; or right click, &amp;ldquo;Toggle suspend&amp;rdquo;).&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Side effect&lt;/strong&gt;: cards/notes from the deck will no longer show up for review. At the&#xA;same time, your past progress is kept, should you ever want to unarchive them.&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: archive a deck&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>obsidian: type * for a bullet point, not ** bold
      </title>
      <link>https://perrotta.dev/2026/07/obsidian-type-for-a-bullet-point-not-bold/</link>
      <pubDate>Fri, 24 Jul 2026 10:04:46 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/07/obsidian-type-for-a-bullet-point-not-bold/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: in &lt;a href=&#34;https://obsidian.md&#34;&gt;Obsidian&lt;/a&gt;, out-of-the-box,&#xA;typing &lt;code&gt;*&lt;/code&gt; at the start of a new line emits &lt;code&gt;*|*&lt;/code&gt; (an empty bold pair, cursor in&#xA;the middle) instead of starting a bullet point.&lt;/p&gt;&#xA;&lt;p&gt;The culprit is &lt;strong&gt;Settings → Editor → Auto pair Markdown syntax&lt;/strong&gt;. With it on,&#xA;every &lt;code&gt;*&lt;/code&gt; auto-inserts its closing &lt;code&gt;*&lt;/code&gt;, so a &lt;code&gt;*&lt;/code&gt; followed by a space never gets&#xA;the chance to become a list marker. In fact, we get a bullet point followed by&#xA;a plain &lt;code&gt;*&lt;/code&gt;, which we then have to delete.&lt;/p&gt;&#xA;&lt;p&gt;To turn this setting off: set &lt;strong&gt;Settings → Editor → Auto pair Markdown syntax&lt;/strong&gt;&#xA;to off.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Now&lt;/strong&gt;: &lt;code&gt;*&lt;/code&gt; followed by a space at the start of a line converts it to a&#xA;bullet&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/07/obsidian-type-for-a-bullet-point-not-bold/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, exactly like &lt;code&gt;-&lt;/code&gt; does.&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;Surely inserting bullet points in Obsidian is a muscle memory artifact&#xA;from migrating from LogSeq.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/07/obsidian-type-for-a-bullet-point-not-bold/#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: obsidian: type * for a bullet point, not ** bold&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>★ 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>brew pin
      </title>
      <link>https://perrotta.dev/2026/07/brew-pin/</link>
      <pubDate>Sat, 18 Jul 2026 14:53:04 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>macos</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/07/brew-pin/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;TIL&lt;/strong&gt;: &lt;a href=&#34;https://docs.brew.sh/FAQ#:~:text=brew%20upgrade%20%3Cformula%3E-,How%20do%20I%20stop%20certain%20formulae%20from%20being%20updated%3F,-To%20stop%20something&#34;&gt;&lt;code&gt;brew pin&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For reasons to be elaborated in another post, I am currently prevented from&#xA;upgrading &lt;a href=&#34;https://logseq.com/&#34;&gt;LogSeq&lt;/a&gt; to its latest version in homebrew:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% brew outdated&#xA;[...]&#xA;logseq (0.10.14) != 2.0.1&#xA;[...]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://news.ycombinator.com/item?id=48896229&#34;&gt;LogSeq v2&lt;/a&gt; introduces breaking&#xA;changes to my workflow. I found this out the hard way. As put by &lt;code&gt;Valodim&lt;/code&gt; in HN:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;And now after several years of complete stagnation, the supposed improvement&#xA;is a database format to fix their technical issues, so I can no longer keep&#xA;all my data as markdown files? At a time when half the edits are done by&#xA;Claude and tracked with jujustu, this is just not useful for me.&lt;/p&gt;&#xA;&lt;p&gt;All I wanted was the original vision, but with less bugs and more quality of&#xA;life features.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;As such, I would like to settle in the current version for now. Pinning to the&#xA;rescue!&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% brew pin logseq&#xA;Warning: logseq has `auto_updates true` and may update itself outside Homebrew despite being pinned.&#xA;&#xA;% brew list --pinned&#xA;logseq&#xA;&#xA;% brew outdated&#xA;[...]&#xA;logseq (0.10.14) != 2.0.1 [pinned at 0.10.14]&#xA;[...]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;That&amp;rsquo;s all.&lt;/p&gt;&#xA;&lt;p&gt;To unpin it in the future:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% brew unpin logseq&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: brew pin&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&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>atuin: global search
      </title>
      <link>https://perrotta.dev/2026/05/atuin-global-search/</link>
      <pubDate>Tue, 26 May 2026 10:40:39 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/05/atuin-global-search/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2025/11/atuin/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;machine 1, day 1: run a bunch of commands&lt;/li&gt;&#xA;&lt;li&gt;machine 2, day 2: I&amp;rsquo;d like to run a subset of the commands I ran yesterday. If&#xA;only I could remember them! I do not have access to machine 1 at the moment.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Enter &lt;a href=&#34;https://atuin.sh/&#34;&gt;&lt;code&gt;atuin&lt;/code&gt;&lt;/a&gt; global search!&lt;/p&gt;&#xA;&lt;p&gt;Assuming that you set up &lt;code&gt;atuin&lt;/code&gt; sync in both machines, all you have to do is&#xA;this:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;enter machine 2, run &lt;code&gt;atuin sync&lt;/code&gt; once, manually&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/05/atuin-global-search/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;thiago.perrotta ~&#xA;% atuin sync&#xA;Uploading 102 records to 0198c192{redacted}d30370fad/history&#xA;  [00:00:00] [##########################] 102/102 (0.0s)3/0 up/down to record store&#xA;Sync complete! 105855 items in history database, force: false&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;press &lt;code&gt;Cmd-R&lt;/code&gt; (or &lt;code&gt;Ctrl-R&lt;/code&gt;), ensure the &lt;a href=&#34;https://docs.atuin.sh/cli/configuration/config/#filter_mode&#34;&gt;filter mode&lt;/a&gt; is set to &lt;code&gt;global&lt;/code&gt;:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;global (default): Search from the full history&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;grep for the desired commands in the interactive TUI that will follow&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;profit!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This is peak PKM! It just works™.&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;Or simply &lt;em&gt;wait&lt;/em&gt; until it happens in the background automatically.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/05/atuin-global-search/#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: atuin: global search&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>★ 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>★ 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>★ 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>atuin: delete account
      </title>
      <link>https://perrotta.dev/2026/05/atuin-delete-account/</link>
      <pubDate>Mon, 18 May 2026 17:49:39 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <category>privacy</category>
      <category>security</category>
      <category>selfhosted</category>
      <guid>https://perrotta.dev/2026/05/atuin-delete-account/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2025/11/atuin/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve been &lt;a href=&#34;https://perrotta.dev/2026/01/atuin-new-machine-setup/&#34;&gt;self-hosting&lt;/a&gt;&#xA;&lt;a href=&#34;https://atuin.sh/&#34;&gt;&lt;code&gt;atuin&lt;/code&gt;&lt;/a&gt; for quite a while now. As such, I no longer need an&#xA;account in the official server (created a long time ago).&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: delete that account.&lt;/p&gt;&#xA;&lt;p&gt;Note that I am currently logged into my self-hosted server.&lt;/p&gt;&#xA;&lt;p&gt;As such, the first step is to switch back to the official server:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% $EDITOR ~/.config/atuin/config.toml&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Then ensure that &lt;code&gt;sync_address&lt;/code&gt; is either commented out or set to&#xA;&lt;code&gt;https://api.atuin.sh&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Now log in to it:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% atuin login --username {username}&#xA;&amp;gt;&amp;gt; insert password, insert key&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And, finally:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% atuin account delete&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Afterwards, switch back to the self-hosted server and run &lt;code&gt;atuin login&lt;/code&gt; again.&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: atuin: delete account&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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/privacy/&#34;&gt;#privacy&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/security/&#34;&gt;#security&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/selfhosted/&#34;&gt;#selfhosted&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>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>anki: auto-sync
      </title>
      <link>https://perrotta.dev/2026/04/anki-auto-sync/</link>
      <pubDate>Sun, 12 Apr 2026 10:38:15 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/04/anki-auto-sync/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/04/anki-corrupted-database/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: enable auto-sync to AnkiWeb.&lt;/p&gt;&#xA;&lt;p&gt;First layer: enable sync on open/close: &lt;code&gt;Preferences &amp;gt; Syncing &amp;gt; Automatically sync on profile open/close&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;Second layer: for manual syncs, press &lt;code&gt;y&lt;/code&gt;&#xA;(&lt;a href=&#34;https://old.reddit.com/r/Anki/comments/1bxrkbn/is_there_a_way_to_sync_automatically_whenever_a/&#34;&gt;source&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;Third layer: install and enable an auto sync add-on such as &lt;a href=&#34;https://ankiweb.net/shared/info/501542723&#34;&gt;this&#xA;one&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;This addon will automatically synchronize your collection with AnkiWeb at time&#xA;intervals you can choose. It will never interrupt you while you are using&#xA;Anki.&lt;/p&gt;&#xA;&lt;p&gt;By default, the first sync will start 1 minute after your last activity. While&#xA;Anki is sitting idle in the background, it will sync every 10 minutes. You can&#xA;change those settings in the options dialog.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Someone forked that add-on to improve upon it, enabling &lt;a href=&#34;https://ankiweb.net/shared/info/226796325&#34;&gt;background auto&#xA;sync&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Should I trust a random add-on though? Even if the Anki community is generally&#xA;decent and well-intentioned, these days we can&amp;rsquo;t trust anyone.&lt;/p&gt;&#xA;&lt;p&gt;I asked &lt;a href=&#34;https://www.anthropic.com/news/claude-code-security&#34;&gt;Opus 4.6&lt;/a&gt; (Claude)&#xA;to analyze it for potential malware:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;⏺ I&amp;#39;ve now read every single source file in the addon. Here&amp;#39;s my analysis:&#xA;&#xA;  ---&#xA;  Malware Analysis: Background Auto Sync (226796325)&#xA;&#xA;  Addon: Background Auto Sync for Anki&#xA;  Author: athulkrishna2015&#xA;  Source: GitHub&#xA;  Fork of: Auto-Sync-Anki-Addon by Robin-Haupt-1&#xA;  License: GPL-3.0&#xA;  Files reviewed: All 8 Python source files &amp;#43; manifest.json&#xA;&#xA;  Verdict: No malware detected. Appears safe.&#xA;&#xA;  What the code actually does&#xA;&#xA;  1. sync_routine.py (core logic) — Sets up timers to periodically call Anki&amp;#39;s built-in&#xA;  mw.col.sync_collection(). Saves/restores window state so sync doesn&amp;#39;t steal focus. All sync goes&#xA;  through Anki&amp;#39;s native sync infrastructure (AnkiWeb auth, mw.pm.sync_auth()).&#xA;  2. utils.py — Single function: has_internet_connection() which opens a TCP socket to 8.8.8.8:53&#xA;  (Google DNS) to check connectivity. This is a standard, benign connectivity check. No data is&#xA;  sent.&#xA;  3. config.py — Reads/writes config to Anki&amp;#39;s own config storage (mw.col.set_config/get_config). No&#xA;   external communication.&#xA;  4. main.py — Wires up hooks (profile_did_open, profile_will_close, sync_will_start,&#xA;  sync_did_finish) and adds a menu item. Standard Anki addon boilerplate.&#xA;  5. log_window.py — Simple in-memory log viewer (QDialog &amp;#43; QTextEdit). No file I/O, no network.&#xA;  6. options_dialog.py — Qt settings dialog with spinboxes/checkboxes. The support tab loads a Ko-fi&#xA;   widget (https://storage.ko-fi.com/cdn/widget/Widget_2.js) via an embedded AnkiWebView. Also&#xA;  displays crypto donation QR codes (BTC, ETH, UPI). These are static images bundled in the addon.&#xA;  7. constants.py — Config key names and defaults. Pure data.&#xA;  8. bump.py / make_ankiaddon.py — Developer build tooling only; not shipped in the .ankiaddon&#xA;  package.&#xA;&#xA;  Specific things I checked for&#xA;&#xA;  ┌────────────────┬────────────────────────────────────────────────────────────────────────────┐&#xA;  │    Concern     │                                  Finding                                   │&#xA;  ├────────────────┼────────────────────────────────────────────────────────────────────────────┤&#xA;  │                │ Only socket.create_connection(&amp;#34;8.8.8.8&amp;#34;, 53) for connectivity check &amp;#43;      │&#xA;  │ Network calls  │ Anki&amp;#39;s own sync API. No external HTTP requests, no telemetry, no phoning   │&#xA;  │                │ home.                                                                      │&#xA;  ├────────────────┼────────────────────────────────────────────────────────────────────────────┤&#xA;  │ File system    │ Only os.path.dirname(__file__) and os.path.join to load bundled QR code    │&#xA;  │ access         │ images. No reading/writing arbitrary files.                                │&#xA;  ├────────────────┼────────────────────────────────────────────────────────────────────────────┤&#xA;  │ Code execution │ None. No exec(), eval(), subprocess, os.system, importlib, or dynamic code │&#xA;  │  / eval        │  loading.                                                                  │&#xA;  ├────────────────┼────────────────────────────────────────────────────────────────────────────┤&#xA;  │ Data           │ No access to deck content, card data, or personal information beyond what  │&#xA;  │ exfiltration   │ Anki&amp;#39;s sync already handles.                                               │&#xA;  ├────────────────┼────────────────────────────────────────────────────────────────────────────┤&#xA;  │ Obfuscation    │ None. Code is clean, readable, well-structured Python.                     │&#xA;  ├────────────────┼────────────────────────────────────────────────────────────────────────────┤&#xA;  │ Suspicious     │ Only standard library (socket, datetime, os, json) and Anki&amp;#39;s own APIs     │&#xA;  │ imports        │ (aqt, aqt.qt).                                                             │&#xA;  ├────────────────┼────────────────────────────────────────────────────────────────────────────┤&#xA;  │                │ Loads JavaScript from storage.ko-fi.com in the support tab — this is a     │&#xA;  │ Ko-fi widget   │ standard donation button, not a concern, and only loads when you open the  │&#xA;  │                │ options dialog&amp;#39;s &amp;#34;Support&amp;#34; tab.                                            │&#xA;  └────────────────┴────────────────────────────────────────────────────────────────────────────┘&#xA;&#xA;  Minor notes (not security concerns)&#xA;&#xA;  - The author has 18 other shared items on AnkiWeb, suggesting an active community member rather&#xA;  than a throwaway account.&#xA;  - The addon is relatively new (updated 2026-03-27) with 0 ratings so far, so there&amp;#39;s limited&#xA;  community vetting.&#xA;  - The code is a clean, well-documented fork of the established Robin-Haupt Auto-Sync addon.&#xA;&#xA;  Bottom line: The code does exactly what it claims — periodic background sync using Anki&amp;#39;s native&#xA;  sync mechanism. No signs of malicious intent, data exfiltration, backdoors, or obfuscated code.&#xA;&#xA;✻ Cooked for 2m 36s&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I am not installing it though, I am happy with the second layer for now.&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: auto-sync&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>Anki: corrupted database
      </title>
      <link>https://perrotta.dev/2026/04/anki-corrupted-database/</link>
      <pubDate>Wed, 08 Apr 2026 00:14:11 +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/04/anki-corrupted-database/</guid>
      <description>&lt;p&gt;♠ Life is hard.&#xA;Today, when opening &lt;a href=&#34;https://apps.ankiweb.net/&#34;&gt;Anki&lt;/a&gt; on macOS:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;DbError { info: &amp;#34;SqliteFailure(Error { code: DatabaseCorrupt, extended_code: 11 }, Some(\&amp;#34;database disk image is malformed\&amp;#34;))&amp;#34;, kind: Other }&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Database corrupt? What is this, are we in the 2000s? Goodness.&lt;/p&gt;&#xA;&lt;p&gt;I have automatic backups enabled. For 4 years I haven&amp;rsquo;t needed them. Today&#xA;is the day. Never say never!&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% ls -lt &amp;#34;$HOME/Library/Application Support/Anki2/Thiago/backups/&amp;#34;&#xA;total 234496&#xA;-rw-r--r--@ 1 tperrotta  staff  3911921 Apr  8 00:12 backup-2026-04-08-00.12.17.colpkg&#xA;-rw-r--r--@ 1 tperrotta  staff  3911921 Apr  7 00:16 backup-2026-04-07-00.16.26.colpkg&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;I try:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;open &amp;#34;$HOME/Library/Application Support/Anki2/Thiago/backups/backup-2026-04-07-00.16.26.colpkg&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;but apparently that file is corrupt as well.&lt;/p&gt;&#xA;&lt;p&gt;I am not particularly worried because I sync my notes to&#xA;&lt;a href=&#34;https://ankiweb.net/&#34;&gt;AnkiWeb&lt;/a&gt;. Even if the entire local collection were corrupt,&#xA;my flashcards are in the cloud.&lt;/p&gt;&#xA;&lt;p&gt;So I decided to simply start from scratch&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2026/04/anki-corrupted-database/#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;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;mv ~/Library/Application\ Support/Anki2/Thiago/collection.anki2 ~/Library/Application\ Support/Anki2/Thiago/collection.anki2.corrupt&#xA;rm -f ~/Library/Application\ Support/Anki2/Thiago/collection.anki2-shm ~/Library/Application\ Support/Anki2/Thiago/collection.anki2-wal&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Then I open Anki.&lt;/p&gt;&#xA;&lt;p&gt;It prompts me to download my decks from AnkiWeb.&lt;/p&gt;&#xA;&lt;p&gt;And now everything works as usual! Last cleanup:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;trash ~/Library/Application\ Support/Anki2/Thiago/collection.anki2.corrupt&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;No idea why this has happened. First time. Life goes on.&lt;/p&gt;&#xA;&lt;p&gt;!next&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/2025/10/anki-find-all-suspended-flashcards/&#34;&gt;Previously&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;The idea was mine. The decision was mine. The LLM suggested the command on&#xA;how to do so. I can still self-troubleshoot, &lt;em&gt;mmmkay&lt;/em&gt;?&amp;#160;&lt;a href=&#34;https://perrotta.dev/2026/04/anki-corrupted-database/#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: Anki: corrupted database&#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>LogSeq: slowness on macOS
      </title>
      <link>https://perrotta.dev/2026/01/logseq-slowness-on-macos/</link>
      <pubDate>Sat, 03 Jan 2026 23:53:13 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>macos</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2026/01/logseq-slowness-on-macos/</guid>
      <description>&lt;p&gt;♠ Last week LogSeq was super slow on my Mac, it was pretty much unusable. I had to&#xA;manually kill its process multiple times as it kept freezing.&lt;/p&gt;&#xA;&lt;p&gt;Eventually I figured out &lt;a href=&#34;https://discuss.logseq.com/t/my-logseq-become-too-slow-recently/31985/4&#34;&gt;the issue&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Then iCloud is the cause for the slowness. This is a known issue and is the&#xA;reason why the developers have built Logseq Sync. Other options for syncing&#xA;that don&amp;rsquo;t impact performance are Git and SyncThing.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;I would like to keep using iCloud at this time as it&amp;rsquo;s (i) free and (ii)&#xA;convenient to access from iOS.&lt;/p&gt;&#xA;&lt;p&gt;The following mitigation seemed to work:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Locate the LogSeq directory in iCloud (&lt;code&gt;~/Library/Mobile Documents/iCloud~com~logseq~logseq/Documents&lt;/code&gt;)&lt;/li&gt;&#xA;&lt;li&gt;Right click the directory in Finder&lt;/li&gt;&#xA;&lt;li&gt;Click &lt;a href=&#34;https://discussions.apple.com/thread/256113094?sortBy=rank&#34;&gt;&amp;lsquo;Keep Downloaded&amp;rsquo;&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Keep Downloaded means the file stays on the device, and even if space is&#xA;needed the file will not be removed [&amp;hellip;]&lt;/p&gt;&#xA;&lt;/blockquote&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: slowness on macOS&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Reordering mobile editing icons in logseq
      </title>
      <link>https://perrotta.dev/2025/12/reordering-mobile-editing-icons-in-logseq/</link>
      <pubDate>Sat, 06 Dec 2025 00:42:32 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2025/12/reordering-mobile-editing-icons-in-logseq/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://bate.dev/posts/logseq-mobile/&#34;&gt;Reordering mobile editing icons in&#xA;logseq&lt;/a&gt; by Colin Bate:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;I found a way to avoid needing to constantly scroll sideways to access the&#xA;icons I need.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;This is why I love the indie web.&lt;/p&gt;&#xA;&lt;p&gt;I was looking for how to do exactly the same operation, for exactly the same&#xA;icon.&lt;/p&gt;&#xA;&lt;p&gt;Isn&amp;rsquo;t it so amazing when a person documents their solutions publicly online, in&#xA;the open? Colin, you are my hero.&lt;/p&gt;&#xA;&lt;p&gt;Update &lt;code&gt;custom.css&lt;/code&gt; in LogSeq settings:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-css&#34;&gt;/* Move icons 3&amp;#43; to order 2 */&#xA;#mobile-editor-toolbar .toolbar-commands &amp;gt; div:nth-child(n&amp;#43;3) {&#xA;  order: 2;&#xA;  color: var(--cyan);&#xA;}&#xA;&#xA;/* Insert icon 11 (brackets) at order 1 */&#xA;#mobile-editor-toolbar .toolbar-commands &amp;gt; div:nth-child(11) {&#xA;  order: 1;&#xA;  color: var(--orange);&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;strong&gt;Side effect&lt;/strong&gt;: The &lt;code&gt;[]&lt;/code&gt; wikilink button will be moved to be the third one in&#xA;the editor toolbar.&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: Reordering mobile editing icons in logseq&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>Snippets manager
      </title>
      <link>https://perrotta.dev/2025/12/snippets-manager/</link>
      <pubDate>Tue, 02 Dec 2025 11:52:39 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2025/12/snippets-manager/</guid>
      <description>&lt;p&gt;♠ Humans are terrible at remembering complex command lines.&lt;/p&gt;&#xA;&lt;p&gt;This issue compounds whenever there is a myriad of commands to remember.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve been thinking for ages on how to address this gap efficiently. I finally&#xA;got a decent workflow.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Unlimited + synchronized shell history: &lt;a href=&#34;https://perrotta.dev/2025/11/atuin/&#34;&gt;&lt;code&gt;atuin&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Text expander: &lt;a href=&#34;https://perrotta.dev/2025/05/espanso-hello-world/&#34;&gt;&lt;code&gt;espanso&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;And now, the missing piece: a snippets manager.&lt;/p&gt;&#xA;&lt;p&gt;There are three good options:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://masscode.io/&#34;&gt;MassCode&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.renfei.org/snippets-lab/&#34;&gt;Snippets Lab&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/knqyf263/pet&#34;&gt;&lt;code&gt;pet&lt;/code&gt;&lt;/a&gt;: command-line&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I am piloting Snippets Lab&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2025/12/snippets-manager/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;. It has integration with&#xA;&lt;a href=&#34;https://www.raycast.com/renfei_song/snippetslab&#34;&gt;Raycast&lt;/a&gt;, and also a system&#xA;tray icon.&lt;/p&gt;&#xA;&lt;p&gt;These three solutions are enough to manage anything I may ever want to recall.&#xA;Commands at my fingertips.&lt;/p&gt;&#xA;&lt;p&gt;We can finish with the cherry on top: &lt;a href=&#34;https://logseq.com/&#34;&gt;LogSeq&lt;/a&gt; entries to&#xA;archive deprecated or &lt;em&gt;potentially&lt;/em&gt; useful commands.&lt;/p&gt;&#xA;&lt;p&gt;From 2026 onwards, no command shall ever be lost.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The aforementioned programs are intended for macOS. Atuin, Espanso,&#xA;MassCode, &lt;code&gt;pet&lt;/code&gt; and LogSeq are cross-platform. Snippets Lab is macOS only.&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 is very comparable to MassCode. This choice was a bit arbitrary.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2025/12/snippets-manager/#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: Snippets manager&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>Anki: find all suspended flashcards
      </title>
      <link>https://perrotta.dev/2025/10/anki-find-all-suspended-flashcards/</link>
      <pubDate>Wed, 08 Oct 2025 19:14:48 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2025/10/anki-find-all-suspended-flashcards/</guid>
      <description>&lt;p&gt;♠ The following queries are useful to find flashcards (notes or cards) in&#xA;&lt;a href=&#34;https://apps.ankiweb.net/&#34;&gt;Anki&lt;/a&gt; that you&amp;rsquo;re struggling with.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;is:suspended&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;tag:leech&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The action item for each should be one of the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;do nothing for now&lt;/li&gt;&#xA;&lt;li&gt;delete the note / card if it&amp;rsquo;s no longer relevant e.g. perhaps it is barely&#xA;used&lt;/li&gt;&#xA;&lt;li&gt;enhance or rewrite the note / card for better retention and then unsuspend it&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a slow process.&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: find all suspended flashcards&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>Daily log
      </title>
      <link>https://perrotta.dev/2025/08/daily-log/</link>
      <pubDate>Wed, 13 Aug 2025 12:02:03 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <category>serenity</category>
      <category>socialmedia</category>
      <guid>https://perrotta.dev/2025/08/daily-log/</guid>
      <description>&lt;p&gt;♠ It&amp;rsquo;s easy to get distracted when using computers connected to the internet.&#xA;Like, errhmm, when you are doing your job.&lt;/p&gt;&#xA;&lt;p&gt;I tend to minimize some distractions by reducing notifications and by&#xA;turning on do not disturb on my phone. Having / using less social media also&#xA;helps.&lt;/p&gt;&#xA;&lt;p&gt;What about Internet distractions in my work laptop though?&lt;/p&gt;&#xA;&lt;p&gt;Lately I&amp;rsquo;ve been trying out a new habit that appears to keep me more focused&#xA;throughout the day.&lt;/p&gt;&#xA;&lt;p&gt;First, I open my note-taking / second brain app (&lt;a href=&#34;https://logseq.com/&#34;&gt;LogSeq&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;Next, create a new journal page for it (&lt;code&gt;Aug 13th, 2025&lt;/code&gt; or &lt;code&gt;2025-08-13&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;One reason I like LogSeq is that it does it automatically for me, every day.&lt;/p&gt;&#xA;&lt;p&gt;Then I create a heading called &amp;ldquo;Daily log&amp;rdquo;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2025/08/daily-log/#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;I think about what to work on next, typically based on ticket prioritization or&#xA;sprint planning or dealing with whatever fire is going on at the moment or a&#xA;&amp;ldquo;20%&amp;rdquo; project to improve overall code health.&lt;/p&gt;&#xA;&lt;p&gt;Then I type in &lt;code&gt;/time&amp;lt;ENTER&amp;gt;&lt;/code&gt;. LogSeq helpfully inserts the current time e.g.&#xA;&lt;code&gt;13:14&lt;/code&gt;. Afterwards, I write a single sentence about what I&amp;rsquo;m going to do. For&#xA;example:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;14:18 Sync docker images for bitnamilegacy&lt;/li&gt;&#xA;&lt;li&gt;14:45 Experiment with pruning in Argo&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This is not intended to be a meticulous report, as it doesn&amp;rsquo;t impact me in any&#xA;way (e.g. for performance reviews).&lt;/p&gt;&#xA;&lt;p&gt;I merely observed that jotting one slice of idea down makes my intent concrete,&#xA;clear(er), and helps me stay focused on it, instead of thinking on the next&#xA;procrastination browser tab to open to get distracted with.&lt;/p&gt;&#xA;&lt;p&gt;There&amp;rsquo;s also a psychological effect wherein observing my accomplishments at the&#xA;end of the day simply feels good.&lt;/p&gt;&#xA;&lt;p&gt;And last but not least, it becomes easier for me to remember what I worked on&#xA;during the day, making my stand-up meetings more comprehensive.&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;Or &amp;ldquo;Daily&amp;rdquo;. The name is not important.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2025/08/daily-log/#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: Daily log&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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;a href=&#34;https://perrotta.dev/tags/socialmedia/&#34;&gt;#socialmedia&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ Logseq template for working out
      </title>
      <link>https://perrotta.dev/2025/06/logseq-template-for-working-out/</link>
      <pubDate>Sun, 22 Jun 2025 02:19:09 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>bestof</category>
      <category>pkm</category>
      <category>serenity</category>
      <guid>https://perrotta.dev/2025/06/logseq-template-for-working-out/</guid>
      <description>&lt;p&gt;♠ Lately I&amp;rsquo;ve been tracking my gym sessions in &lt;a href=&#34;https://logseq.com/&#34;&gt;Logseq&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This workflow has been in place for at least three months, therefore it&amp;rsquo;s stable&#xA;enough by now. Here&amp;rsquo;s the rough idea.&lt;/p&gt;&#xA;&lt;p&gt;First, create a &lt;code&gt;[[Templates]]&lt;/code&gt; page.&lt;/p&gt;&#xA;&lt;p&gt;How to remember whether it&amp;rsquo;s &lt;code&gt;Templates&lt;/code&gt; or &lt;code&gt;Template&lt;/code&gt;? Simple: add an&#xA;&lt;code&gt;alias::template&lt;/code&gt; attribute to the page. It should be the first bullet point.&#xA;Now there&amp;rsquo;s no need to remember: any of them will do.&lt;/p&gt;&#xA;&lt;p&gt;Then add a &lt;code&gt;[[Gym 💪]]&lt;/code&gt; bullet point&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2025/06/logseq-template-for-working-out/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; with &lt;code&gt;alias::gym&lt;/code&gt;. In it, add a&#xA;&lt;code&gt;template::gym&lt;/code&gt; attribute. Within it, add the template content. This is the part&#xA;where you should adapt it to your own desires and goals, but I&amp;rsquo;ll share mine:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;- Location&#xA;&#x9;- [[mygym]] (mylocation1 | mylocation2)&#xA;- Defaults&#xA;&#x9;- 3-4x 8-12&#xA;- Warm-up&#xA;&#x9;- XX min what&#xA;- Upper&#xA;&#x9;- Exercise: 25 -&amp;gt; 30&#xA;- Lower&#xA;&#x9;-&#xA;- Cooldown&#xA;&#x9;- XX min what&#xA;- Protein recovery&#xA;&#x9;- XX g (what)&#xA;- Body weight&#xA;&#x9;- XX kg (gym | home)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A brief explanation:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;location: links to the page of each gym, where I can add details such as its&#xA;Wi-Fi password, how much drinks cost there, etc.&lt;/li&gt;&#xA;&lt;li&gt;defaults: the baseline for the session – how many sets, how many repetitions&#xA;in each?&lt;/li&gt;&#xA;&lt;li&gt;warm-up: what did I do, for how many minutes?&lt;/li&gt;&#xA;&lt;li&gt;upper: a bucket to group upper-body exercises: arms, chest, abs, etc.&lt;/li&gt;&#xA;&lt;li&gt;lower: a bucket to group lower-body exercises: legs, calves, glutes, etc.&lt;/li&gt;&#xA;&lt;li&gt;cooldown: what did I do, for how many minutes?&lt;/li&gt;&#xA;&lt;li&gt;protein recovery: in grams, what did I drink or eat?&lt;/li&gt;&#xA;&lt;li&gt;body weight: in kilos, and where did I measure it?&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2025/06/logseq-template-for-working-out/#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This template has served me well. The most important part is the one that&#xA;contains the exercises (upper and lower).&lt;/p&gt;&#xA;&lt;p&gt;Now, let&amp;rsquo;s say I am going to the gym today.&lt;/p&gt;&#xA;&lt;p&gt;First, I open the journal page (&lt;code&gt;[[2025-06-22]]&lt;/code&gt;).&#xA;Then I type in &lt;code&gt;/template gym&lt;/code&gt;. This inserts the template above.&lt;/p&gt;&#xA;&lt;p&gt;Now I click &lt;code&gt;[[Gym 💪]]&lt;/code&gt; to open up the gym page.&lt;/p&gt;&#xA;&lt;p&gt;The gym page contains a detailed explanation of my current goals and workflows.&#xA;In particular, it has an exercises reference section that looks like this (the&#xA;numbers are made up):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;* # Exercises&#xA;* Upper&#xA;  * Biceps: 10 -&amp;gt; 12&#xA;  * Triceps: 18 -&amp;gt; 20&#xA;  * Butterfly normal: 20 -&amp;gt; 25&#xA;  * Butterfly reverse: 20 -&amp;gt; 25&#xA;  [...]&#xA;* Lower&#xA;  * Hip addiction: 17 -&amp;gt; 20&#xA;  * Hip abduction: 15 -&amp;gt; 20&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Each entry tracks the latest weight and the one before it, which makes the&#xA;progression explicit (and doubles-down as a motivation factor!).&lt;/p&gt;&#xA;&lt;p&gt;Now, because this is an advanced PKM, the backlink we inserted earlier with the&#xA;template shows up under &amp;ldquo;linked references&amp;rdquo; at the bottom. And this is the magic&#xA;that makes Logseq useful for this kind of tracking: all gym entries are&#xA;accessible at a glance, connected to the main &lt;code&gt;[[Gym 💪]]&lt;/code&gt; page.&lt;/p&gt;&#xA;&lt;p&gt;During the workout, I use the appropriate weight from the gym page as an input&#xA;to the corresponding daily note entry, and slowly increase it in-between sets.&lt;/p&gt;&#xA;&lt;p&gt;For example, let&amp;rsquo;s say that for biceps the reference entry is &lt;code&gt;Biceps: 10 -&amp;gt; 12&lt;/code&gt;. Then, for today&amp;rsquo;s workout, I will add an entry like &lt;code&gt;Biceps: 12 -&amp;gt; 13 -&amp;gt; 14&lt;/code&gt;, starting with &lt;code&gt;12&lt;/code&gt;, the latest reference value.&lt;/p&gt;&#xA;&lt;p&gt;Repeat for each exercise.&lt;/p&gt;&#xA;&lt;p&gt;At the end of the workout, I update the reference entries with the progress of&#xA;the day. For example, the updated entry for biceps becomes &lt;code&gt;* Biceps: 12 -&amp;gt; 14&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I never liked to go to the gym, but now I am starting to enjoy it, because I&#xA;feel this approach brings many self-motivating benefits:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;there&amp;rsquo;s a detailed record of every single workout that I do, down to the day&#xA;and the exercise / weight in each set. These entries are psychologically&#xA;powerful, they motivate me more than smartwatches and/or gym / workouts apps&lt;/li&gt;&#xA;&lt;li&gt;the progression ensures I am consistent and pick up where I left off in the&#xA;previous session. There&amp;rsquo;s no need to guess any longer which weight to use, I&#xA;know exactly which one to use, and whether it was difficult or easy last time&#xA;(as I also track this information in the reference).&lt;/li&gt;&#xA;&lt;li&gt;reduced risk of injury as I am increasing the weights slowly, and being&#xA;mindful of the ones that incur a lot of stress and/or strain on my muscles&lt;/li&gt;&#xA;&lt;li&gt;ability to track goals and be realistic about them, and even estimate when&#xA;I&amp;rsquo;ll be able to reach them, based on historical progression.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I tried to use gym apps before, but they were never effective. They are often&#xA;complicated and bloated. The advantage of keeping the format plain and flexible&#xA;in the PKM is that it can suit all my needs. In fact, I could even bring pen and&#xA;paper to the gym instead of my smartphone if needed, as there&amp;rsquo;s absolutely no&#xA;need for internet access when updating these entries, and no lock-in whatsoever.&lt;/p&gt;&#xA;&lt;p&gt;There&amp;rsquo;s nothing revolutionary in my approach. Its core is merely: (i)&#xA;(annotated!) consistency and (ii) ability to shape the system to the format that&#xA;suits/fits my needs.&lt;/p&gt;&#xA;&lt;p&gt;Consistency is very important. Before adopting this system, I would always guess&#xA;which weight to use for each exercise. But there are too many of them, and as&#xA;such it&amp;rsquo;s quite difficult to keep track of them all in my head.&lt;/p&gt;&#xA;&lt;p&gt;The format flexibility is also important. The key is to shape a system to your&#xA;needs, not the other way around. With smartphone and smartwatch apps, I always&#xA;felt that I had to adapt myself to the input format the app expects, which is&#xA;painful from an UX perspective.&lt;/p&gt;&#xA;&lt;p&gt;And now it is time to work out again 💪&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;Yes, including the emoji. Life is short to skip having fun.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2025/06/logseq-template-for-working-out/#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;There are tiny differences, therefore I like to note down whether I used&#xA;the scale from the gym or the one at home.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2025/06/logseq-template-for-working-out/#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: Logseq template for working out&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&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>Logseq: open page in sidebar
      </title>
      <link>https://perrotta.dev/2025/05/logseq-open-page-in-sidebar/</link>
      <pubDate>Wed, 14 May 2025 00:31:30 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2025/05/logseq-open-page-in-sidebar/</guid>
      <description>&lt;p&gt;♠ To open a page in the sidebar in &lt;a href=&#34;https://logseq.com/&#34;&gt;Logseq&lt;/a&gt;, hold Shift +&#xA;click the &lt;code&gt;[[page]]&lt;/code&gt; / &lt;code&gt;#page&lt;/code&gt; link.&lt;/p&gt;&#xA;&lt;p&gt;Pages can be stacked in the sidebar, à la &lt;a href=&#34;https://dwm.suckless.org/&#34;&gt;dwm&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: Logseq: open page in sidebar&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>Logseq: list all pages of a tag
      </title>
      <link>https://perrotta.dev/2025/05/logseq-list-all-pages-of-a-tag/</link>
      <pubDate>Sun, 04 May 2025 13:24:52 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2025/05/logseq-list-all-pages-of-a-tag/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: Given a couple of pages in &lt;a href=&#34;https://logseq.com/&#34;&gt;Logseq&lt;/a&gt;&#xA;tagged with a given &lt;code&gt;content&lt;/code&gt; tag:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;tags:: content&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;dynamically list all of them.&lt;/p&gt;&#xA;&lt;p&gt;We can do so with the following logseq query&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2025/05/logseq-list-all-pages-of-a-tag/#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;&#xA;&lt;pre&gt;&lt;code class=&#34;language-markdown&#34;&gt;#&amp;#43;BEGIN_QUERY&#xA;{&#xA;  :title &amp;#34;Ideas 💡 (-&amp;gt;)&amp;#34;&#xA;  :query (property :tags &amp;#34;idea&amp;#34;)&#xA;}&#xA;#&amp;#43;END_QUERY&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This is a static query, not meant to be changed.&lt;/p&gt;&#xA;&lt;p&gt;Alternatively it&amp;rsquo;s possible to create a live query, which allows one to tweak it&#xA;on-the-fly:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-markdown&#34;&gt;{{query (property :tags &amp;#34;idea&amp;#34;)}}&lt;/code&gt;&lt;/pre&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;The query syntax is somewhat a blend of &lt;a href=&#34;https://orgmode.org&#34;&gt;orgmode&lt;/a&gt; +&#xA;emacs lisp from emacs.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2025/05/logseq-list-all-pages-of-a-tag/#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: Logseq: list all pages of a tag&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>Logseq: aliases
      </title>
      <link>https://perrotta.dev/2025/03/logseq-aliases/</link>
      <pubDate>Sat, 01 Mar 2025 15:55:20 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2025/03/logseq-aliases/</guid>
      <description>&lt;p&gt;♠ In &lt;a href=&#34;https://logseq.com/&#34;&gt;Logseq&lt;/a&gt;, I have an entry called &amp;ldquo;Trips&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;In a topic in my daily note, I want to use the &lt;code&gt;#trip&lt;/code&gt; tag to link to it.&lt;/p&gt;&#xA;&lt;p&gt;However, &lt;code&gt;#trip&lt;/code&gt; links to a distinct page, called &amp;ldquo;Trip&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: How can we &amp;ldquo;merge&amp;rdquo; the two entries, effectively treating&#xA;them as one?&lt;/p&gt;&#xA;&lt;p&gt;Use &lt;a href=&#34;https://unofficial-logseq-docs.gitbook.io/unofficial-logseq-docs/beginner-to-advance-features/aliases&#34;&gt;aliases&lt;/a&gt;: In &amp;ldquo;Trips&amp;rdquo;, in the very first bullet point, type &lt;code&gt;::alias&lt;/code&gt;. The&#xA;auto-completion pops up. Type in &amp;ldquo;trip&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;That&amp;rsquo;s all. Linking with &lt;code&gt;[[trip]]&lt;/code&gt; or &lt;code&gt;#trip&lt;/code&gt; now points out to &amp;ldquo;Trips&amp;rdquo;.&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: Logseq: aliases&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>Anki: insert emoji on macOS
      </title>
      <link>https://perrotta.dev/2025/01/anki-insert-emoji-on-macos/</link>
      <pubDate>Sat, 11 Jan 2025 00:28:48 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>macos</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2025/01/anki-insert-emoji-on-macos/</guid>
      <description>&lt;p&gt;♠ There&amp;rsquo;s a longstanding bug in &lt;a href=&#34;https://apps.ankiweb.net/&#34;&gt;Anki&lt;/a&gt; on macOS: it&amp;rsquo;s&#xA;not possible to insert an emoji in the editor view via the system emoji picker.&lt;/p&gt;&#xA;&lt;p&gt;Whenever you click an emoji, the emoji picker closes whilst nothing is inserted.&lt;/p&gt;&#xA;&lt;p&gt;This has always annoyed me.&lt;/p&gt;&#xA;&lt;p&gt;Today I found a&#xA;&lt;a href=&#34;https://forums.ankiweb.net/t/macos-emoji-picker-not-working-in-editor-view/4061&#34;&gt;workaround&lt;/a&gt; (thanks Luc!):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;For anyone who comes across this. I figured out a quick workaround. You have&#xA;to open the Emoji-Picker-Keyboard on your Mac and then select the Emoji and&#xA;pull it into the editor window with your mouse.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;It works indeed!&lt;/p&gt;&#xA;&lt;p&gt;My previous alternative was to use the emoji picker to insert an emoji in&#xA;another application (e.g. the Notes.app), and then manually cut and paste 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: Anki: insert emoji on macOS&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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;a href=&#34;https://perrotta.dev/tags/pkm/&#34;&gt;#pkm&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Logseq: linking and backlinking
      </title>
      <link>https://perrotta.dev/2025/01/logseq-linking-and-backlinking/</link>
      <pubDate>Mon, 06 Jan 2025 22:49:44 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2025/01/logseq-linking-and-backlinking/</guid>
      <description>&lt;p&gt;♠ This is the first post about LogSeq / PKM. Run before it&amp;rsquo;s &lt;a href=&#34;https://en.wikipedia.org/wiki/The_Paradox_of_Choice&#34;&gt;too&#xA;late&lt;/a&gt;!&lt;/p&gt;&#xA;&lt;p&gt;Expect more of these as I find myself slowly migrating from&#xA;&lt;a href=&#34;https://obsidian.md/&#34;&gt;Obsidian&lt;/a&gt; to &lt;a href=&#34;https://logseq.com/&#34;&gt;Logseq&lt;/a&gt;. More on that&#xA;later.&lt;/p&gt;&#xA;&lt;p&gt;When creating pages in logseq, there are &lt;strong&gt;two&lt;/strong&gt; basic forms to link to other pages,&#xA;and they are essentially equivalent.&lt;/p&gt;&#xA;&lt;p&gt;The first one is to use a &lt;code&gt;#hashtag&lt;/code&gt; (or simply &amp;rsquo;tag&amp;rsquo;). For example:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Books to read in 2010:&#xA;&#xA;- The Hitchhiker&amp;#39;s Guide to the Galaxy by Douglas Adams #book #fiction&#xA;- Harry Potter and the Prisoner of Azkaban by J.K. Rowling #book #fiction&#xA;- Elite da Tropa by André Batista, Rodrigo Pimentel &amp;amp; Luiz Eduardo Soares #book #nonfiction&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;em&gt;^alpha&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;Under the hood it creates 3 pages: &lt;code&gt;Book&lt;/code&gt;, &lt;code&gt;Fiction&lt;/code&gt; and &lt;code&gt;Nonfiction&lt;/code&gt;. Clicking&#xA;any of these hashtags opens up the corresponding page. In the page it&amp;rsquo;s possible&#xA;to find a backlink to the original page / block that links to it.&lt;/p&gt;&#xA;&lt;p&gt;The second one is to use double brackets. For example:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;- Elite da Tropa is a Brazilian [[book]] written by the ex-police officers André&#xA;  Batista and Rodrigo Pimentel together with Luiz Eduardo Soares. It was first&#xA;  published in 2006. The book originated the film Elite Squad.&#xA;  - Source: https://en.wikipedia.org/wiki/Elite_da_Tropa&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;em&gt;^bravo&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;Clicking &lt;code&gt;[[book]]&lt;/code&gt; goes to the same page as &lt;code&gt;#book&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Why are there two forms? I don&amp;rsquo;t know. But here&amp;rsquo;s what I learned: it doesn&amp;rsquo;t&#xA;matter which one you choose to use, as they are effectively equivalent. For&#xA;example, you could have written instead:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;- Elite da Tropa is a Brazilian #book written by the ex-police officers André&#xA;  Batista and Rodrigo Pimentel together with Luiz Eduardo Soares. It was first&#xA;  published in 2006. The book originated the film Elite Squad.&#xA;  - Source: https://en.wikipedia.org/wiki/Elite_da_Tropa&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;em&gt;^charlie&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&amp;hellip;the effect would have been the same.&lt;/p&gt;&#xA;&lt;p&gt;The idiomatic style seems to favour the use of double brackets when writing&#xA;prose (i.e. &lt;em&gt;bravo&lt;/em&gt;), and the use of hashtags when &amp;ldquo;tagging&amp;rdquo; or qualifying&#xA;sentences (i.e. &lt;em&gt;alpha&lt;/em&gt;). That said, intermixing them is harmless.&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: Logseq: linking and backlinking&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>★ Anki workflow
      </title>
      <link>https://perrotta.dev/2024/12/anki-workflow/</link>
      <pubDate>Mon, 23 Dec 2024 00:12:52 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>bestof</category>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2024/12/anki-workflow/</guid>
      <description>&lt;p&gt;♠ I&amp;rsquo;ve been using &lt;a href=&#34;https://apps.ankiweb.net/&#34;&gt;Anki&lt;/a&gt; since 2-3 years ago to keep up&#xA;with German vocabulary and grammar. I had originally started with Duolingo.&lt;/p&gt;&#xA;&lt;p&gt;In the beginning my workflow was quite basic.&#xA;Then I created &lt;a href=&#34;https://perrotta.dev/2024/02/anki-custom-language-card/&#34;&gt;custom language&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./&#34;&gt;cards&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;After you install Anki, you need to set up a Note Type to keep your flashcards&#xA;formatted as you like. Anki comes with a few basic Note Types, but they aren&amp;rsquo;t&#xA;suited for learning Japanese.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;(&lt;a href=&#34;https://tatsumoto.neocities.org/blog/setting-up-anki&#34;&gt;via&lt;/a&gt;). The advantage of&#xA;creating a custom note type (language card) is that I can format it the way I&#xA;want.&lt;/p&gt;&#xA;&lt;p&gt;On top of it I tweaked my Anki deck settings to optimize it for language learning.&lt;/p&gt;&#xA;&lt;p&gt;I adopted the &lt;a href=&#34;https://web.archive.org/web/20210203165239/https://massimmersionapproach.com/table-of-contents/anki/low-key-anki/intro&#34;&gt;Low-Key Anki&#xA;setup&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The Low-Key Anki setup is a series of counterintuitive simplifications one can&#xA;make to Anki&amp;rsquo;s algorithm that result in a significant boost in efficiency, as&#xA;well as a considerable reduction in the stress associated with reviewing cards&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Furthermore, Soren Bjornstad has helpfully written &lt;a href=&#34;https://controlaltbackspace.org/precise/&#34;&gt;some&#xA;tips&lt;/a&gt; about designing flashcards&#xA;effectively, some of which I gladly adopted.&lt;/p&gt;&#xA;&lt;p&gt;And last but not least, &lt;a href=&#34;https://refold.la/roadmap/stage-1/a/anki-setup&#34;&gt;Refold&lt;/a&gt;&#xA;provided me with a step-by-step breakdown on how to configure Anki for language&#xA;learning.&lt;/p&gt;&#xA;&lt;h2 id=&#34;references&#34;&gt;&#xA;  References&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/12/anki-workflow/#references&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://refold.la/roadmap/stage-1/a/anki-setup&#34;&gt;https://refold.la/roadmap/stage-1/a/anki-setup&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://web.archive.org/web/20210203165239/https://massimmersionapproach.com/table-of-contents/anki/low-key-anki/intro&#34;&gt;https://web.archive.org/web/20210203165239/https://massimmersionapproach.com/table-of-contents/anki/low-key-anki/intro&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://tatsumoto.neocities.org/blog/setting-up-anki.html&#34;&gt;https://tatsumoto.neocities.org/blog/setting-up-anki.html&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://controlaltbackspace.org/precise/&#34;&gt;https://controlaltbackspace.org/precise/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://digitalwords.net/anki/low-key/&#34;&gt;https://digitalwords.net/anki/low-key/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://michaelnotebook.com/mmsw/&#34;&gt;https://michaelnotebook.com/mmsw/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://borretti.me/article/effective-spaced-repetition&#34;&gt;https://borretti.me/article/effective-spaced-repetition&lt;/a&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: Anki workflow&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>★ Default apps 2024
      </title>
      <link>https://perrotta.dev/2024/12/default-apps-2024/</link>
      <pubDate>Sat, 21 Dec 2024 16:02:54 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>bestof</category>
      <category>dev</category>
      <category>macos</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2024/12/default-apps-2024/</guid>
      <description>&lt;p&gt;♠ The list of my default apps for this year.&lt;/p&gt;&#xA;&lt;p&gt;In the past I would maintain an &lt;a href=&#34;https://uses.tech/&#34;&gt;&amp;ldquo;uses&amp;rdquo;&lt;/a&gt; page in my blog, but I no longer believe in it.&#xA;User needs change all the time, and it&amp;rsquo;s a chore to keep them up-to-date.&#xA;People shouldn&amp;rsquo;t be defined by the software they use.&lt;/p&gt;&#xA;&lt;p&gt;That said, having a clean snapshot of the software I use at a fixed point in time isn&amp;rsquo;t a bad proposition.&#xA;It doesn&amp;rsquo;t need to be maintained.&#xA;I will probably look back at it within 5 years and laugh at myself for how many things changed.&#xA;And also for how many didn&amp;rsquo;t.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Browser: Google Chrome on macOS, Chromium on Linux, Safari on iOS.&lt;/li&gt;&#xA;&lt;li&gt;Search: A combination of Google and DuckDuckGo (mostly for their &lt;a href=&#34;https://duckduckgo.com/bangs&#34;&gt;!bangs&lt;/a&gt;).&lt;/li&gt;&#xA;&lt;li&gt;Writing: A combination of VSCode, &lt;code&gt;vim&lt;/code&gt; and &lt;a href=&#34;https://github.com/MarkEdit-app/MarkEdit&#34;&gt;MarkEdit&lt;/a&gt; (macOS markdown editor app). I never got around to long-form writing in Obsidian or Logseq, however it&amp;rsquo;s something I strive to.&lt;/li&gt;&#xA;&lt;li&gt;Cloud File Storage: There&amp;rsquo;s no need to share this. Basic OpSec. Why would people share it?&lt;/li&gt;&#xA;&lt;li&gt;Chat: WhatsApp remains king in terms of popularity, despite Telegram being superior from an architectural and usability perspective for power users. Facebook Messenger is officially dead at this point. And I&amp;rsquo;m too much of a millennial for all other apps (Discord, Matrix, etc). Disappearing messages exist in all of these, except Instagram.&lt;/li&gt;&#xA;&lt;li&gt;Scheduling: There&amp;rsquo;s no real choice here. You use the platform your employer uses. Otherwise, Google Calendar is the most sensible choice other than self-hosting.&lt;/li&gt;&#xA;&lt;li&gt;Video Calls: Ditto. I am way too used to Google Meet to justify switching to an alternative at this point.&lt;/li&gt;&#xA;&lt;li&gt;Music: Spotify, hands down. YouTube Music is a good fallback. There&amp;rsquo;s no need to pay for YouTube Premium for music, do your research.&lt;/li&gt;&#xA;&lt;li&gt;Podcasts: Overcast on iOS.&lt;/li&gt;&#xA;&lt;li&gt;Password Management: Once again, why would you share this?&lt;/li&gt;&#xA;&lt;li&gt;Code Editor: VScode and &lt;code&gt;vim&lt;/code&gt;. Maybe I&amp;rsquo;ll switch to &lt;code&gt;neovim&lt;/code&gt; at some point. I refrain from using IDEs in general but, when I need to, JetBrains is the answer. I tried &lt;a href=&#34;https://zed.dev/&#34;&gt;&lt;code&gt;zed&lt;/code&gt;&lt;/a&gt; this year but wasn&amp;rsquo;t convinced, and their core team is quite small. The flurry of &amp;ldquo;AI&amp;rdquo;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/12/default-apps-2024/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; editors should be ignored, as none of them are likely to stick long-term. Instead, it&amp;rsquo;s better to invest in &amp;ldquo;AI&amp;rdquo; tooling that is editor agnostic; for example, Simon Willison&amp;rsquo;s &lt;a href=&#34;https://github.com/simonw/llm&#34;&gt;&lt;code&gt;llm&lt;/code&gt;&lt;/a&gt;, or GitHub Copilot.&lt;/li&gt;&#xA;&lt;li&gt;Terminal: iTerm2 on macOS. I haven&amp;rsquo;t used desktop linux in a while (:sad:), but I&amp;rsquo;d probably still stick to Tilix and/or Alacritty there. I no longer use hterm (ChromeOS).&lt;/li&gt;&#xA;&lt;li&gt;VPN: Unless you&amp;rsquo;re rolling your own, it doesn&amp;rsquo;t matter too much. Avoid the big players if you can afford to.&lt;/li&gt;&#xA;&lt;li&gt;Bookmarks: None. &lt;a href=&#34;https://www.goodreads.com/book/show/25614984-spark-joy&#34;&gt;Absolutely none&lt;/a&gt;. When I need to store &lt;em&gt;transient&lt;/em&gt; link lists, I use my Second Brain app to do so.&lt;/li&gt;&#xA;&lt;li&gt;Read It Later: Ditto as above. Otherwise: starring articles on Miniflux, or keeping Safari tabs open until I get to them, or parking a handful of items in an &amp;ldquo;inbox&amp;rdquo; browser bookmarks folder.&lt;/li&gt;&#xA;&lt;li&gt;Mail Client: The official clients of my email providers. No agnostic app at this time. It&amp;rsquo;s especially inconvenient to do so on iOS.&lt;/li&gt;&#xA;&lt;li&gt;Mail Server: N/A.&lt;/li&gt;&#xA;&lt;li&gt;Launcher: &lt;code&gt;Cmd-Space&lt;/code&gt; on macOS a.k.a. Spotlight. I keep Raycast around but I rarely use it. On Linux &lt;code&gt;i3-dmenu-desktop&lt;/code&gt; is still my favorite.&lt;/li&gt;&#xA;&lt;li&gt;Screenshots: &lt;code&gt;Cmd-Shift-4&lt;/code&gt; on macOS, or &lt;code&gt;scrot&lt;/code&gt; on Linux.&lt;/li&gt;&#xA;&lt;li&gt;Menu Bar: &lt;a href=&#34;https://github.com/dwarvesf/hidden&#34;&gt;Hidden Bar&lt;/a&gt;. It&amp;rsquo;s free, and available as a cask on homebrew.&lt;/li&gt;&#xA;&lt;li&gt;Containers: Rancher Desktop.&lt;/li&gt;&#xA;&lt;li&gt;Automation: None. I tried Hammerspoon this year but found no use for it.&lt;/li&gt;&#xA;&lt;li&gt;Second Brain: A mixture of Obsidian and Logseq. Which I&amp;rsquo;d really like to end, it would be easier to have a single app to rule them all, as they both support multiple vaults / graphs anyway (e.g. to partition personal vs work notes).&lt;/li&gt;&#xA;&lt;li&gt;Operating System: &lt;a href=&#34;https://alpinelinux.org/&#34;&gt;Alpine Linux&lt;/a&gt; is my current favorite for servers, and I&amp;rsquo;m biased anyway because I maintain a couple of aports (packages) there. For desktop, it&amp;rsquo;s awfully hard to use anything other than macOS ever since M1 processors got released. I miss Linux desktop from time to time but realistically it&amp;rsquo;s no longer an intrinsic goal of mine; that said, I&amp;rsquo;d likely go back to my beloved Arch Linux should that ever reoccur.&lt;/li&gt;&#xA;&lt;li&gt;Shell: &lt;code&gt;zsh&lt;/code&gt; + &lt;a href=&#34;https://grml.org/zsh/&#34;&gt;&lt;code&gt;grml-zsh-config&lt;/code&gt;&lt;/a&gt;, no change here. Sometimes I think of migrating to &lt;code&gt;fish&lt;/code&gt;, but the POSIX incompability always discourages me to do so.&lt;/li&gt;&#xA;&lt;li&gt;Terminal Multiplexer: &lt;code&gt;tmux&lt;/code&gt;, but only for remote sessions (&lt;code&gt;ssh&lt;/code&gt;). Locally I tend to just open new terminal tabs on VSCode and/or iTerm2. Alas, &lt;code&gt;tmux&lt;/code&gt; + &lt;code&gt;VSCode&lt;/code&gt; do not play well together anyway (citation needed, for another day).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This post was inspired by &lt;a href=&#34;https://micro.webology.dev/2024/12/19/default-apps.html&#34;&gt;https://micro.webology.dev/2024/12/19/default-apps.html&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;For the correct way to refer to them, pick one of: LLMs, Gen AI, or &amp;ldquo;AI&amp;rdquo;. &lt;em&gt;Never&lt;/em&gt; drop the quotes when using the plain term! Otherwise you fall into the same trap for using the term &amp;ldquo;crypto&amp;rdquo; to distinguish between cryptography and cryptocurrency.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/12/default-apps-2024/#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: Default apps 2024&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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/macos/&#34;&gt;#macos&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>logseq: backlog
      </title>
      <link>https://perrotta.dev/2024/11/logseq-backlog/</link>
      <pubDate>Tue, 26 Nov 2024 18:53:22 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2024/11/logseq-backlog/</guid>
      <description>&lt;p&gt;♠ Assume you use &lt;code&gt;TODO&lt;/code&gt; and &lt;code&gt;DOING&lt;/code&gt; for workflow tracking in&#xA;&lt;a href=&#34;https://logseq.com/&#34;&gt;Logseq&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Assume you use an &lt;code&gt;#instrospect&lt;/code&gt; tag.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: how to define a single page / live query that aggregates&#xA;all of the above?&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-markdown&#34;&gt;{{query (OR (task TODO DOING) [[introspect]])}}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Unraveling:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;[[introspect]]&lt;/code&gt; refers to the &lt;code&gt;#introspect&lt;/code&gt; tag&lt;/li&gt;&#xA;&lt;li&gt;A live query can be added with &lt;code&gt;/query&lt;/code&gt;, which is represented as &lt;code&gt;{{query }}&lt;/code&gt;&#xA;under the hood.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;More information: check out the &lt;a href=&#34;https://hub.logseq.com/features/av5LyiLi5xS7EFQXy4h4K8/getting-started-with-advanced-queries/8xwSRJNVKFJhGSvJUxs5B2&#34;&gt;logseq&#xA;hub&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: logseq: backlog&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>★ Anki: custom language card (cont.)
      </title>
      <link>https://perrotta.dev/2024/09/anki-custom-language-card-cont./</link>
      <pubDate>Sun, 22 Sep 2024 13:02:39 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>bestof</category>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2024/09/anki-custom-language-card-cont./</guid>
      <description>&lt;p&gt;♠ This post builds upon the previous &lt;a href=&#34;https://perrotta.dev/2024/02/anki-custom-language-card/&#34;&gt;Anki: custom language card&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;searching-word-boundaries&#34;&gt;&#xA;  Searching word boundaries&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#searching-word-boundaries&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;When searching for a word such as &lt;em&gt;Mann&lt;/em&gt;, results such as &lt;em&gt;Mannschaft&lt;/em&gt; come up.&lt;/p&gt;&#xA;&lt;p&gt;To search accounting for the word boundary, like a typical &lt;code&gt;\bMann\b&lt;/code&gt; regex, use&#xA;&lt;code&gt;w:&lt;/code&gt;. In this example: &lt;code&gt;w:Mann&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;searching-ignoring-accents&#34;&gt;&#xA;  Searching ignoring accents&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#searching-ignoring-accents&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;When searching for a word with Umlauts such as &lt;em&gt;Über&lt;/em&gt;, you should type it&#xA;exactly as is.&lt;/p&gt;&#xA;&lt;p&gt;If you are lazy or do not recall where the umlaut falls, perhaps you would think&#xA;of searching for &lt;em&gt;uber&lt;/em&gt;, however that does not work.&lt;/p&gt;&#xA;&lt;p&gt;To make it work, prepend &lt;code&gt;nc:&lt;/code&gt; to the word. In this case: &lt;code&gt;nc:uber&lt;/code&gt; will&#xA;properly match &lt;em&gt;über&lt;/em&gt;. NC stands for non-combining.&lt;/p&gt;&#xA;&lt;h2 id=&#34;searching-word-boundaries-whilst-ignoring-accents&#34;&gt;&#xA;  Searching word boundaries &lt;strong&gt;whilst&lt;/strong&gt; ignoring accents&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#searching-word-boundaries-whilst-ignoring-accents&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Is it possible to combine the two aforementioned operators? For example, to&#xA;match &lt;em&gt;für&lt;/em&gt;. Unfortunately, &lt;a href=&#34;https://stackoverflow.com/questions/79011851/anki-how-to-match-while-using-both-w-and-nc-simultaneously&#34;&gt;it is&#xA;not&lt;/a&gt;.&#xA;Anki does not support &lt;code&gt;w:nc:fur&lt;/code&gt; nor &lt;code&gt;nc:w:fur&lt;/code&gt;, which is unfortunate. &lt;em&gt;Schade&lt;/em&gt;!&lt;/p&gt;&#xA;&lt;p&gt;In this case the best compromise would be to search for &lt;code&gt;w:für&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;adding-images-to-flashcards&#34;&gt;&#xA;  Adding images to flashcards&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#adding-images-to-flashcards&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;It is pretty straightforward: Right click the image in your favorite web&#xA;browser, copy it, and then paste it (Ctrl/Cmd + V) into Anki. The image is&#xA;automatically imported.&lt;/p&gt;&#xA;&lt;p&gt;No-brainer image sources:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://dict.cc/&#34;&gt;dict.cc&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://images.google.com/&#34;&gt;Google Images&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Nowadays it would also be natural&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; to use &amp;ldquo;AI&amp;rdquo; to generate images.&lt;/p&gt;&#xA;&lt;h2 id=&#34;providing-examples-style&#34;&gt;&#xA;  Providing examples: style&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#providing-examples-style&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;To illustrate with a concrete example:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;: &lt;u&gt;Ja&lt;/u&gt;, genau.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt;: Das ist &lt;u&gt;ja&lt;/u&gt; komisch.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Affirmative&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;The structure:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Bold&lt;/strong&gt; numbers to disambiguate&lt;/li&gt;&#xA;&lt;li&gt;&lt;u&gt;Underscore&lt;/u&gt; the word in question to emphasize it&lt;/li&gt;&#xA;&lt;li&gt;&lt;em&gt;Italicize&lt;/em&gt; everything that is meta or an explanation about the word&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;To highlight substrings, e.g. &lt;em&gt;Mann&lt;/em&gt; in &lt;em&gt;Mannschaft&lt;/em&gt;, use underscores&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#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;h2 id=&#34;tags&#34;&gt;&#xA;  Tags&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#tags&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;I seldom tag notes because there is no need for categorization, all cards are&#xA;treated the same way. Tagging is only useful in two scenarios:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;for grouping / retrieval: for example, if you want to make custom study&#xA;sessions for a specific domain / area (e.g. animals, programming, trips)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;for provenance annotations: to make it easier to remember where a given note&#xA;came from (e.g. &amp;ldquo;textbook&amp;rdquo;, &amp;ldquo;my german teacher&amp;rdquo;, &amp;ldquo;blog&amp;rdquo;, &amp;ldquo;podcast&amp;rdquo;, &amp;ldquo;work&amp;rdquo;)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Adding tags creates the burden of managing and standardizing them. You do not&#xA;want to spend valuable mental effort derailing from your main task.&lt;/p&gt;&#xA;&lt;h2 id=&#34;sources&#34;&gt;&#xA;  Sources&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#sources&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.ankiweb.net/searching.html&#34;&gt;https://docs.ankiweb.net/searching.html&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&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;Albeit deeply unnecessary and wasteful (energy-wise).&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#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;This principle is not strict. I often interchange bold and underscore.&#xA;Choose whichever feels more natural in the appropriate context.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/09/anki-custom-language-card-cont./#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: custom language card (cont.)&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>★ Anki: custom language card
      </title>
      <link>https://perrotta.dev/2024/02/anki-custom-language-card/</link>
      <pubDate>Sat, 03 Feb 2024 13:02:21 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>bestof</category>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2024/02/anki-custom-language-card/</guid>
      <description>&lt;p&gt;♠ The more time you spent playing with &lt;a href=&#34;https://apps.ankiweb.net/&#34;&gt;Anki&lt;/a&gt;, the&#xA;more opinionated you become.&lt;/p&gt;&#xA;&lt;p&gt;Upon reading &lt;a href=&#34;https://fluent-forever.com/index.html&#34;&gt;Fluent Forever&lt;/a&gt; by Gabriel&#xA;Wyner, I got an itch to create my own Anki note template for learning&#xA;languages.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-template&#34;&gt;&#xA;  The template&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/02/anki-custom-language-card/#the-template&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;There&amp;rsquo;s no point explaining how to create a new template; the excellent &lt;a href=&#34;https://docs.ankiweb.net/templates/intro.html&#34;&gt;Anki&#xA;documentation&lt;/a&gt; already does so.&#xA;Instead, I&amp;rsquo;ll just list and explain the template I created.&lt;/p&gt;&#xA;&lt;p&gt;The template is called &amp;ldquo;Deutsch Language Card 🇩🇪&amp;rdquo;. It has four fields:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Front&lt;/li&gt;&#xA;&lt;li&gt;Front Example&lt;/li&gt;&#xA;&lt;li&gt;Back&lt;/li&gt;&#xA;&lt;li&gt;Striked&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Front and Back come from the built-in template. There&amp;rsquo;s nothing special about&#xA;them. I use &amp;ldquo;Front&amp;rdquo; for the canonical term in the foreign language I&amp;rsquo;m&#xA;learning, and &amp;ldquo;Back&amp;rdquo; for the explanation in the base / native language I&amp;rsquo;m&#xA;mostly familiar with&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2024/02/anki-custom-language-card/#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;Here&amp;rsquo;s an example:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Front: das Buch&#xA;Back: book 📚&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Whenever possible I include one or more emojis 😃 in the &amp;ldquo;Back&amp;rdquo; field.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;strong&gt;canonicalization&lt;/strong&gt; of the &amp;ldquo;Front&amp;rdquo; field is important, and one of the best&#xA;(key, even!) features of Anki. It will smartly detect (and prevent!) duplicates&#xA;from being created. It is case sensitive, therefore it&amp;rsquo;s important to create&#xA;one convention and stick to it.&lt;/p&gt;&#xA;&lt;p&gt;&amp;ldquo;Front Example&amp;rdquo; is used to complement the &amp;ldquo;Front&amp;rdquo; field. It consists of one or&#xA;both of the following:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A phrase or sentence containing the Front term.&lt;/li&gt;&#xA;&lt;li&gt;A picture representing the Front term.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;To increase overall retention, it&amp;rsquo;s always best to add cues familiar to your&#xA;context.&lt;/p&gt;&#xA;&lt;p&gt;Add phrases that resonate with you or that you find in textbooks or&#xA;blog posts that resonate with you. In my experience, adding random phrases is&#xA;not effective.&lt;/p&gt;&#xA;&lt;p&gt;Add images that represent well that you&amp;rsquo;re describing and that&#xA;resonate with you. Photos that you take yourself are also fair game!&lt;/p&gt;&#xA;&lt;p&gt;&amp;ldquo;Striked&amp;rdquo; is to disambiguate synonyms or false cognates. For example:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Front: der Sturm&#xA;Back: storm ⛈️&#xA;Striked: das Gewitter, das Unwetter&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;When I am reviewing the Back card, I want to cue myself not to think about the&#xA;striked terms.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-source-code&#34;&gt;&#xA;  The source code&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/02/anki-custom-language-card/#the-source-code&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;h3 id=&#34;the-front-card&#34;&gt;&#xA;  The Front card&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/02/anki-custom-language-card/#the-front-card&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;{{Front}} {{tts de_DE:Front}}&#xA;&#xA;{{#Front Example}}&#xA;&amp;lt;br&amp;gt;&#xA;&amp;lt;i&amp;gt;{{Front Example}}&amp;lt;/i&amp;gt; {{tts de_DE:Front Example}}&#xA;{{/Front Example}}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The front card includes a text-to-speech sample that is generated on-the-fly.&#xA;It works very well on macOS and iOS. In fact, that&amp;rsquo;s main reason why the&#xA;template is called &amp;ldquo;Deutsch Language Card&amp;rdquo; instead of just &amp;ldquo;Language Card&amp;rdquo;. The&#xA;text-to-speech engine is customized to have an accent in the given language.&#xA;For (High) German, that is &lt;code&gt;de_DE&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;the-back-card&#34;&gt;&#xA;  The Back card&#xA;  &lt;a class=&#34;heading-anchor&#34; href=&#34;https://perrotta.dev/2024/02/anki-custom-language-card/#the-back-card&#34; aria-label=&#34;Link to this section&#34;&gt;#&lt;/a&gt;&#xA;&lt;/h3&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;{{Back}}&#xA;&#xA;{{#Striked}}&#xA;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&#xA;&amp;lt;s&amp;gt;{{Striked}}&amp;lt;/s&amp;gt;&#xA;{{/Striked}}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The striked terms are &lt;del&gt;striked&lt;/del&gt;, as you would expect.&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;Interestingly I prefer to use English most of the time, even though it is&#xA;not my mother tongue.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2024/02/anki-custom-language-card/#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: Anki: custom language card&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>Anki: find all notes with an empty field
      </title>
      <link>https://perrotta.dev/2024/01/anki-find-all-notes-with-an-empty-field/</link>
      <pubDate>Mon, 29 Jan 2024 00:06:49 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>dev</category>
      <category>pkm</category>
      <guid>https://perrotta.dev/2024/01/anki-find-all-notes-with-an-empty-field/</guid>
      <description>&lt;p&gt;♠ Gabriel Wyner recommends, in its &lt;a href=&#34;https://fluent-forever.com/index.html&#34;&gt;Fluent&#xA;Forever&lt;/a&gt; book, that each&#xA;&lt;a href=&#34;https://apps.ankiweb.net/&#34;&gt;Anki&lt;/a&gt; note (card) has at least one image&#xA;associated to it. This is intended to improve overall retention.&lt;/p&gt;&#xA;&lt;p&gt;Back when I started my German Anki deck for language learning, I did not add&#xA;any images. Now I find myself slowly backfilling my already existing notes&#xA;with images. However, the more images I add, the harder it becomes to find&#xA;notes without images.&lt;/p&gt;&#xA;&lt;p&gt;Upon reading the &lt;a href=&#34;https://docs.ankiweb.net/&#34;&gt;Anki manual&lt;/a&gt; I figured out a way to find out which notes are still missing images:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Open Anki.&lt;/li&gt;&#xA;&lt;li&gt;Open the deck you want to modify – in my case, &lt;code&gt;Languages::German&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Click &amp;ldquo;Browse&amp;rdquo;.&lt;/li&gt;&#xA;&lt;li&gt;Type in &lt;code&gt;deck:current &amp;quot;Front Example:&amp;quot;&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&amp;ldquo;Front Example&amp;rdquo; is the name of the field of my note template wherein I add images; you should replace it with the corresponding one you use. This syntax isn&amp;rsquo;t intuitive at all. Initially I was trying something like &lt;code&gt;-&amp;quot;Front Example:*&amp;quot;&lt;/code&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: Anki: find all notes with an empty field&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&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>
  </channel>
</rss>
