<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Inkstone</title><link>https://me.125520.xyz/</link><description>A minimal bilingual Hugo template for longreads.</description><generator>Hugo</generator><language>en</language><managingEditor>Jason</managingEditor><copyright>© 2026 Jason</copyright><lastBuildDate>Thu, 07 May 2026 14:15:04 +0000</lastBuildDate><atom:link href="https://me.125520.xyz/en/tags/index.xml" rel="self" type="application/rss+xml"/><item><title>Wiring Claude Code into macOS Notifications + Bark Push</title><link>https://me.125520.xyz/en/claude-code-mac-bark-notify/</link><pubDate>Thu, 07 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/claude-code-mac-bark-notify/</guid><description>Translating a Windows PowerShell gist to macOS, then bolting on a Bark channel so the phone buzzes when long jobs finish too.</description><content:encoded><![CDATA[<blockquote>
<p>Origin story: spotted a <a href="https://gist.github.com/RisenMyth/6297cab96eb9dec912cc6c126cbed965" target="_blank" rel="noopener">Windows gist that wires Claude Code into system notifications<span class="external-mark" aria-hidden="true">↗</span></a>
, written in PowerShell, useless on a Mac. Rewrote it for macOS, then added a <a href="https://day.app/" target="_blank" rel="noopener">Bark<span class="external-mark" aria-hidden="true">↗</span></a>
 channel — when a long job finishes and you&rsquo;ve wandered off, the phone in your pocket should be the one that pings.</p>
</blockquote>
<h2 id="1-the-shape-of-it">1. The shape of it</h2>
<p>Claude Code&rsquo;s hook system exposes a set of lifecycle events. For &ldquo;notify me&rdquo;, you only need two:</p>
<ul>
<li><strong><code>Stop</code></strong> — the model finished its turn. Time to ring the bell.</li>
<li><strong><code>Notification</code></strong> — the model wants confirmation or input (permission prompts, questions). More urgent.</li>
</ul>
<p>The hook command receives JSON on stdin: <code>cwd</code> (project path), <code>transcript_path</code> (full JSONL conversation), and <code>Notification</code> events also carry a <code>message</code>.</p>
<p>Design choices:</p>
<ul>
<li><strong>Single Python file</strong> — macOS ships <code>python3</code> by default, so no jq / curl JSON-escaping ceremony.</li>
<li><strong>Local toast prefers <code>terminal-notifier</code></strong> — use it if installed (clickable, supports group dedup); fall back to <code>osascript</code> otherwise. Zero install required.</li>
<li><strong>Bark is opt-in</strong> — only fires when <code>BARK_KEY</code> is set. Failures are silent; the hook&rsquo;s exit code stays clean.</li>
<li><strong>No chmod</strong> — see the &ldquo;gotchas&rdquo; section below. The script isn&rsquo;t executable; we invoke it as <code>python3 path/to/notify.py</code>.</li>
</ul>
<h2 id="2-the-script-claudehooksnotifypy">2. The script: <code>~/.claude/hooks/notify.py</code></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="ch">#!/usr/bin/env python3</span>
</span></span><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;Claude Code notification hook for macOS.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">Local toast (osascript or terminal-notifier) + optional Bark push.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">Usage: notify.py &lt;Stop|Notification|...&gt;
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">Reads JSON from stdin (Claude Code hook payload):
</span></span></span><span class="line"><span class="cl"><span class="s2">  cwd               -&gt; current working directory
</span></span></span><span class="line"><span class="cl"><span class="s2">  transcript_path   -&gt; path to JSONL transcript (Stop event)
</span></span></span><span class="line"><span class="cl"><span class="s2">  message           -&gt; notification message (Notification event)
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">Environment variables (all optional):
</span></span></span><span class="line"><span class="cl"><span class="s2">  BARK_KEY            Bark device key. If unset, Bark push is skipped.
</span></span></span><span class="line"><span class="cl"><span class="s2">  BARK_SERVER         Bark server (default: https://api.day.app).
</span></span></span><span class="line"><span class="cl"><span class="s2">  BARK_GROUP          Notification group (default: ClaudeCode).
</span></span></span><span class="line"><span class="cl"><span class="s2">  BARK_SOUND          Notification sound (default: minuet).
</span></span></span><span class="line"><span class="cl"><span class="s2">  BARK_ICON           Custom icon URL.
</span></span></span><span class="line"><span class="cl"><span class="s2">  BARK_STOP_LEVEL     Level for Stop events (default: passive).
</span></span></span><span class="line"><span class="cl"><span class="s2">  BARK_NOTIFY_LEVEL   Level for Notification events (default: timeSensitive).
</span></span></span><span class="line"><span class="cl"><span class="s2">                      Valid: active | timeSensitive | passive | critical.
</span></span></span><span class="line"><span class="cl"><span class="s2">  CLAUDE_NOTIFY_OFF   If set to &#34;1&#34;, suppress all notifications.
</span></span></span><span class="line"><span class="cl"><span class="s2">&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">json</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">shutil</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">subprocess</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">urllib.request</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">TITLE_PREFIX</span> <span class="o">=</span> <span class="s2">&#34;ClaudeCode&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">MAX_BODY_LEN</span> <span class="o">=</span> <span class="mi">200</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">read_stdin_json</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">raw</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">stdin</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">raw</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">raw</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">last_assistant_text</span><span class="p">(</span><span class="n">transcript_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">p</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">transcript_path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">p</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="n">p</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&#34;r&#34;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s2">&#34;utf-8&#34;</span><span class="p">,</span> <span class="n">errors</span><span class="o">=</span><span class="s2">&#34;replace&#34;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">lines</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()[</span><span class="o">-</span><span class="mi">30</span><span class="p">:]</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">lines</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">entry</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="cl">        <span class="n">msg</span> <span class="o">=</span> <span class="n">entry</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;message&#34;</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">msg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;role&#34;</span><span class="p">)</span> <span class="o">!=</span> <span class="s2">&#34;assistant&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="cl">        <span class="n">content</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;content&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">text</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">text</span> <span class="o">=</span> <span class="n">content</span>
</span></span><span class="line"><span class="cl">        <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="n">block</span> <span class="ow">in</span> <span class="n">content</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">block</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span> <span class="ow">and</span> <span class="n">block</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;type&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="s2">&#34;text&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                    <span class="n">t</span> <span class="o">=</span> <span class="n">block</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                    <span class="k">if</span> <span class="n">t</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">                        <span class="n">text</span> <span class="o">=</span> <span class="n">t</span>
</span></span><span class="line"><span class="cl">                        <span class="k">break</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">text</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">text</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">truncate</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">s</span> <span class="o">=</span> <span class="p">(</span><span class="n">s</span> <span class="ow">or</span> <span class="s2">&#34;&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">s</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">s</span><span class="p">[:</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&#34;…&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">send_mac_notification</span><span class="p">(</span><span class="n">title</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">body</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">tn</span> <span class="o">=</span> <span class="n">shutil</span><span class="o">.</span><span class="n">which</span><span class="p">(</span><span class="s2">&#34;terminal-notifier&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">tn</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="p">[</span><span class="n">tn</span><span class="p">,</span> <span class="s2">&#34;-title&#34;</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="s2">&#34;-message&#34;</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                 <span class="s2">&#34;-sound&#34;</span><span class="p">,</span> <span class="s2">&#34;Glass&#34;</span><span class="p">,</span> <span class="s2">&#34;-group&#34;</span><span class="p">,</span> <span class="s2">&#34;claude-code&#34;</span><span class="p">,</span> <span class="s2">&#34;-ignoreDnD&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                <span class="n">check</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">DEVNULL</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">DEVNULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span>
</span></span><span class="line"><span class="cl">        <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">esc</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">s</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&#34;</span><span class="se">\\</span><span class="s2">&#34;</span><span class="p">,</span> <span class="s2">&#34;</span><span class="se">\\\\</span><span class="s2">&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;&#34;&#39;</span><span class="p">,</span> <span class="s1">&#39;</span><span class="se">\\</span><span class="s1">&#34;&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">script</span> <span class="o">=</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="sa">f</span><span class="s1">&#39;display notification &#34;</span><span class="si">{</span><span class="n">esc</span><span class="p">(</span><span class="n">body</span><span class="p">)</span><span class="si">}</span><span class="s1">&#34; &#39;</span>
</span></span><span class="line"><span class="cl">        <span class="sa">f</span><span class="s1">&#39;with title &#34;</span><span class="si">{</span><span class="n">esc</span><span class="p">(</span><span class="n">title</span><span class="p">)</span><span class="si">}</span><span class="s1">&#34; sound name &#34;Glass&#34;&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="p">[</span><span class="s2">&#34;osascript&#34;</span><span class="p">,</span> <span class="s2">&#34;-e&#34;</span><span class="p">,</span> <span class="n">script</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">            <span class="n">check</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">DEVNULL</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">DEVNULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">send_bark_push</span><span class="p">(</span><span class="n">title</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">body</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">key</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;BARK_KEY&#34;</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">key</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">server</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;BARK_SERVER&#34;</span><span class="p">,</span> <span class="s2">&#34;https://api.day.app&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">&#34;/&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">event</span> <span class="o">==</span> <span class="s2">&#34;Notification&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">level</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;BARK_NOTIFY_LEVEL&#34;</span><span class="p">,</span> <span class="s2">&#34;timeSensitive&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">event</span> <span class="o">==</span> <span class="s2">&#34;Stop&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">level</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;BARK_STOP_LEVEL&#34;</span><span class="p">,</span> <span class="s2">&#34;passive&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">level</span> <span class="o">=</span> <span class="s2">&#34;active&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">payload</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;title&#34;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;body&#34;</span><span class="p">:</span> <span class="n">body</span> <span class="ow">or</span> <span class="s2">&#34; &#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;group&#34;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;BARK_GROUP&#34;</span><span class="p">,</span> <span class="s2">&#34;ClaudeCode&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;level&#34;</span><span class="p">:</span> <span class="n">level</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;sound&#34;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;BARK_SOUND&#34;</span><span class="p">,</span> <span class="s2">&#34;minuet&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">icon</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;BARK_ICON&#34;</span><span class="p">,</span> <span class="s2">&#34;&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">        <span class="n">payload</span><span class="p">[</span><span class="s2">&#34;icon&#34;</span><span class="p">]</span> <span class="o">=</span> <span class="n">icon</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">req</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">server</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">data</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">ensure_ascii</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&#34;utf-8&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">method</span><span class="o">=</span><span class="s2">&#34;POST&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;Content-Type&#34;</span><span class="p">:</span> <span class="s2">&#34;application/json; charset=utf-8&#34;</span><span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="n">urllib</span><span class="o">.</span><span class="n">request</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> <span class="k">as</span> <span class="n">r</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">r</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">main</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;CLAUDE_NOTIFY_OFF&#34;</span><span class="p">)</span> <span class="o">==</span> <span class="s2">&#34;1&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">event</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">else</span> <span class="s2">&#34;Stop&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">data</span> <span class="o">=</span> <span class="n">read_stdin_json</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">cwd</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;cwd&#34;</span><span class="p">)</span> <span class="ow">or</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">project</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">cwd</span><span class="p">)</span> <span class="k">if</span> <span class="n">cwd</span> <span class="k">else</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">event</span> <span class="o">==</span> <span class="s2">&#34;Stop&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">title</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">TITLE_PREFIX</span><span class="si">}</span><span class="s2"> - </span><span class="si">{</span><span class="n">project</span><span class="si">}</span><span class="s2">&#34;</span> <span class="k">if</span> <span class="n">project</span> <span class="k">else</span> <span class="n">TITLE_PREFIX</span>
</span></span><span class="line"><span class="cl">        <span class="n">body</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">transcript</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;transcript_path&#34;</span><span class="p">)</span> <span class="ow">or</span> <span class="s2">&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">transcript</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">body</span> <span class="o">=</span> <span class="n">last_assistant_text</span><span class="p">(</span><span class="n">transcript</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">body</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="n">body</span> <span class="o">=</span> <span class="s2">&#34;Task completed, please review results.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">elif</span> <span class="n">event</span> <span class="o">==</span> <span class="s2">&#34;Notification&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">title</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">TITLE_PREFIX</span><span class="si">}</span><span class="s2"> - Needs Attention&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">project</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">title</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">title</span><span class="si">}</span><span class="s2"> - </span><span class="si">{</span><span class="n">project</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">body</span> <span class="o">=</span> <span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;message&#34;</span><span class="p">)</span> <span class="ow">or</span> <span class="s2">&#34;&#34;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> \
</span></span><span class="line"><span class="cl">            <span class="ow">or</span> <span class="s2">&#34;Claude is waiting for your input or approval.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">title</span> <span class="o">=</span> <span class="n">TITLE_PREFIX</span>
</span></span><span class="line"><span class="cl">        <span class="n">body</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;Event received: </span><span class="si">{</span><span class="n">event</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">body</span> <span class="o">=</span> <span class="n">truncate</span><span class="p">(</span><span class="n">body</span><span class="p">,</span> <span class="n">MAX_BODY_LEN</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">send_mac_notification</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">body</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">send_bark_push</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="n">event</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</span></span></code></pre></div><p>A few details worth flagging:</p>
<ul>
<li><strong>Walking the transcript backwards</strong> — read the last 30 JSONL lines, iterate in reverse, take the first entry where <code>role == &quot;assistant&quot;</code> with non-empty text. The <code>content</code> field can be either a string or an array depending on SDK version; both shapes are handled.</li>
<li><strong>Truncation uses <code>…</code></strong> — a single ellipsis character, not three ASCII dots. Saves two bytes for actual prose.</li>
<li><strong>Bark <code>level</code> differs by event</strong> — <code>Stop</code> defaults to <code>passive</code> (silent, just lands in the push list), <code>Notification</code> defaults to <code>timeSensitive</code> (pierces Focus mode). Long jobs finishing shouldn&rsquo;t shriek; mid-task confirmations must.</li>
<li><strong>Silent failure</strong> — Bark unreachable, osascript erroring, transcript missing — all caught and swallowed. A hook should never wedge the model.</li>
</ul>
<h2 id="3-wiring-it-into-claudesettingsjson">3. Wiring it into <code>~/.claude/settings.json</code></h2>
<p>Merge this block into <code>settings.json</code>, <strong>preserving your existing <code>env / permissions / enabledPlugins</code></strong> etc.:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;Notification&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;matcher&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 /Users/you/.claude/hooks/notify.py Notification&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;timeout&#34;</span><span class="p">:</span> <span class="mi">15</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;Stop&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;matcher&#34;</span><span class="p">:</span> <span class="s2">&#34;&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;python3 /Users/you/.claude/hooks/notify.py Stop&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;timeout&#34;</span><span class="p">:</span> <span class="mi">15</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>matcher: &quot;&quot;</code> is &ldquo;match anything&rdquo; — <code>Stop</code> and <code>Notification</code> don&rsquo;t have sub-matchers anyway. The <code>timeout: 15</code> seconds is a backstop; timing out doesn&rsquo;t break the main flow.</p>
<div class="callout callout-warn" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
  <div class="callout-body"><p class="callout-title">Path must be absolute</p>
    The hook command&rsquo;s working directory is unpredictable — it depends on which project Claude is sitting in at the time. <code>~/.claude/hooks/notify.py</code> won&rsquo;t tilde-expand here. Spell it out: <code>/Users/&lt;you&gt;/.claude/hooks/notify.py</code>.
  </div>
</div>

<h2 id="4-enabling-bark">4. Enabling Bark</h2>
<p>Bark is a long-running iOS push tool. The free key comes from <a href="https://day.app/" target="_blank" rel="noopener">day.app<span class="external-mark" aria-hidden="true">↗</span></a>
. Install the app and the home screen shows a URL like <code>https://api.day.app/abc123xyz/</code> — the middle slug is your device key.</p>
<p>Drop it into the <code>env</code> block of <code>settings.json</code> (hooks inherit env from there):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;env&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;BARK_KEY&#34;</span><span class="p">:</span> <span class="s2">&#34;abc123xyz&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Quick reference for the optional knobs:</p>
<table>
  <thead>
      <tr>
          <th>Variable</th>
          <th>Default</th>
          <th>Purpose</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>BARK_SERVER</code></td>
          <td><code>https://api.day.app</code></td>
          <td>Override for self-hosted Bark</td>
      </tr>
      <tr>
          <td><code>BARK_GROUP</code></td>
          <td><code>ClaudeCode</code></td>
          <td>Notification group (folds on phone)</td>
      </tr>
      <tr>
          <td><code>BARK_SOUND</code></td>
          <td><code>minuet</code></td>
          <td>Sound name</td>
      </tr>
      <tr>
          <td><code>BARK_STOP_LEVEL</code></td>
          <td><code>passive</code></td>
          <td>Level for &ldquo;task finished&rdquo; pushes</td>
      </tr>
      <tr>
          <td><code>BARK_NOTIFY_LEVEL</code></td>
          <td><code>timeSensitive</code></td>
          <td>Level for &ldquo;needs your input&rdquo; pushes</td>
      </tr>
      <tr>
          <td><code>CLAUDE_NOTIFY_OFF</code></td>
          <td>(unset)</td>
          <td>Set to <code>1</code> to mute everything temporarily</td>
      </tr>
  </tbody>
</table>
<h2 id="5-verification">5. Verification</h2>
<p>With <code>BARK_KEY</code> set, fire a manual Notification simulation:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">BARK_KEY</span><span class="o">=</span>your_key <span class="nb">echo</span> <span class="s1">&#39;{&#34;cwd&#34;:&#34;/tmp&#34;,&#34;message&#34;:&#34;test&#34;}&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  <span class="p">|</span> python3 ~/.claude/hooks/notify.py Notification
</span></span></code></pre></div><p>Expected:</p>
<ol>
<li>A macOS toast pops in the top-right corner.</li>
<li>A Bark notification arrives on your phone, grouped under <code>ClaudeCode</code>, level <code>timeSensitive</code>.</li>
</ol>
<p>To preview local-only behavior, just unset <code>BARK_KEY</code> for the call.</p>
<h2 id="6-gotchas">6. Gotchas</h2>
<div class="callout callout-warn" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
  <div class="callout-body"><p class="callout-title">macOS notification permissions</p>
    <code>osascript display notification</code> posts under the identity of the <strong>terminal app that spawned it</strong> (Terminal / iTerm / Ghostty / Warp). If nothing appears at all: System Settings → Notifications → find the terminal in the list → allow notifications.
  </div>
</div>

<p><strong>Hook not firing?</strong> The Claude Code settings watcher only watches directories that already had a settings file at session start. If <code>.claude/</code> was created mid-session, edits may not reload. Open the <code>/hooks</code> menu once (forces a reload), or restart the Claude Code session.</p>
<p><strong><code>chmod</code> denied in your permissions?</strong> My settings include <code>Bash(chmod:*)</code> in <code>permissions.deny</code>, so the script can&rsquo;t be <code>chmod +x</code>&rsquo;d. Fix: invoke via <code>python3 path/to/notify.py</code> so the executable bit is irrelevant. Bonus — it&rsquo;s more explicit and removes a hidden piece of state.</p>
<p><strong>Body too long?</strong> The script caps at <code>MAX_BODY_LEN = 200</code> (199 chars + <code>…</code>). macOS Notification Center will truncate too, but capping early avoids ugly mid-JSON breakage on the Bark side.</p>
<p><strong>Want to dial it back?</strong> <code>Stop</code> fires every turn — easy to find noisy. Two ways out:</p>
<ul>
<li>The Bark side already uses <code>BARK_STOP_LEVEL = passive</code> — silent push, lands in the list only.</li>
<li>For local silence on Stop too: add <code>if event == &quot;Stop&quot;: return</code> to the top of <code>send_mac_notification</code>. Five-line change.</li>
</ul>
<h2 id="7-where-to-take-it-next">7. Where to take it next</h2>
<p>Saving these for future me:</p>
<ul>
<li><strong>Telegram / Lark / Slack</strong> — rename <code>send_bark_push</code> to <code>send_remote_push</code>, dispatch on a <code>REMOTE_KIND</code> env var. Bark is just one of many.</li>
<li><strong>Sharper Notification copy</strong> — currently I just pass through whatever <code>message</code> the model sent. Could branch on <code>tool_name</code> (if hook payload starts including it) for sharper titles.</li>
<li><strong>Debounce a burst</strong> — multiple <code>Stop</code> events within 5s collapsed into one. Right now every turn rings.</li>
<li><strong>Stats</strong> — append a line to <code>~/.claude/hooks/notify.log</code> per fire. A week&rsquo;s worth of &ldquo;how many turns ran, how often the model got blocked on input&rdquo; tells you something interesting.</li>
</ul>
<hr>
<p>You set this up once and forget about it. When the model finishes a turn or stalls waiting for input, a soft chime in the top-right and a buzz in your pocket — long jobs can finally run while you make a coffee.</p>
]]></content:encoded></item><item><title>T11e Callout Smoke Test</title><link>https://me.125520.xyz/en/t11e-callout-smoke/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11e-callout-smoke/</guid><description>Integration check for the callout shortcode across the four supported types and title variants.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11e. The callout shortcode has four supported types — note / tip / warn / danger — wired up in <code>layouts/partials/icon.html</code> and styled in <code>assets/css/components.css</code>. Any other type falls back to an icon-less shell, so this page only exercises the four real ones.</p>
</blockquote>
<h2 id="1-all-four-types-with-title">1. All four types, with title</h2>
<div class="callout callout-note" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></div>
  <div class="callout-body"><p class="callout-title">Note</p>
    Default type. 3px grey rule on the left, neutral icon.
  </div>
</div>

<div class="callout callout-tip" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 12.7V18h8v-3.3A7 7 0 0 0 12 2z"/></svg></div>
  <div class="callout-body"><p class="callout-title">Tip</p>
    Green rule, green icon. Use for hidden usage hints and small suggestions.
  </div>
</div>

<div class="callout callout-warn" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></div>
  <div class="callout-body"><p class="callout-title">Warning</p>
    Amber rule. Operations with side effects or trade-offs.
  </div>
</div>

<div class="callout callout-danger" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg></div>
  <div class="callout-body"><p class="callout-title">Danger</p>
    Vermilion rule on a soft pink ground, sourced from the site accent. Use for irreversible operations.
  </div>
</div>

<h2 id="2-without-title">2. Without title</h2>
<div class="callout callout-note" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></div>
  <div class="callout-body">
    With no title, the body starts on the first line.
  </div>
</div>

<div class="callout callout-tip" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 12.7V18h8v-3.3A7 7 0 0 0 12 2z"/></svg></div>
  <div class="callout-body">
    Good for one-line reminders.
  </div>
</div>

<h2 id="3-nested-markdown">3. Nested markdown</h2>
<div class="callout callout-note" role="note">
  <div class="callout-icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></div>
  <div class="callout-body"><p class="callout-title">Nested test</p>
    The callout body runs through <code>RenderString</code>, so <strong>bold</strong>, <a href="/about/">internal links</a>
, and <code>inline code</code> should all render.
  </div>
</div>

<h2 id="self-check-list">Self-check list</h2>
<ul>
<li><input disabled="" type="checkbox"> The four types use distinct colors (grey / green / amber / vermilion)</li>
<li><input disabled="" type="checkbox"> All four icon partials resolve — no empty <code>&lt;div class=&quot;callout-icon&quot;&gt;</code></li>
<li><input disabled="" type="checkbox"> Variants with a title show <code>&lt;p class=&quot;callout-title&quot;&gt;</code> in bold</li>
<li><input disabled="" type="checkbox"> Nested markdown renders correctly (bold / link / inline code)</li>
<li><input disabled="" type="checkbox"> All four types remain readable in dark mode</li>
</ul>
]]></content:encoded></item><item><title>T11f Pullquote Smoke Test</title><link>https://me.125520.xyz/en/t11f-pullquote-smoke/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11f-pullquote-smoke/</guid><description>Integration check for the pullquote shortcode inside the prose container, with and without an author.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11f. The pullquote shortcode was added in E8; it emits <code>&lt;blockquote class=&quot;pullquote&quot;&gt;</code> and is styled by <code>prose.css</code>. This page covers both shapes — with and without an author — and one nested-markdown case.</p>
</blockquote>
<h2 id="1-with-author">1. With author</h2>

<blockquote class="pullquote">
  The truly brave dare to face a bleak life head-on.
  <cite>— Lu Xun</cite>
</blockquote>

<h2 id="2-without-author">2. Without author</h2>

<blockquote class="pullquote">
  &ldquo;Good enough&rdquo; is not the ceiling of taste — it is the ticket of admission.
  
</blockquote>

<h2 id="3-inner-with-markdown">3. Inner with markdown</h2>

<blockquote class="pullquote">
  <strong>Good writing</strong> precedes <a href="/about/">style</a>
, and precedes <code>tooling</code>.
  <cite>— An editor</cite>
</blockquote>

<h2 id="self-check-list">Self-check list</h2>
<ul>
<li><input disabled="" type="checkbox"> Both shapes adopt prose pullquote styling (large quote glyph / centered or left-aligned / font-size larger than body)</li>
<li><input disabled="" type="checkbox"> With-author variant renders <code>&lt;cite&gt;— Lu Xun&lt;/cite&gt;</code> at a smaller size</li>
<li><input disabled="" type="checkbox"> Without-author variant emits no empty <code>&lt;cite&gt;</code></li>
<li><input disabled="" type="checkbox"> Nested markdown renders correctly (bold / link / inline code)</li>
<li><input disabled="" type="checkbox"> Borders and text remain readable in dark mode</li>
</ul>
]]></content:encoded></item><item><title>T11g Gallery Smoke Test</title><link>https://me.125520.xyz/en/t11g-gallery-smoke/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11g-gallery-smoke/</guid><description>Integration check for the gallery shortcode — runtime JSON load and lightGallery overlay.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11g. The gallery shortcode itself only emits a placeholder div; the <code>shortcode_gallery</code> partial fetches the JSON at runtime, hands it to justifiedGallery for layout, and to lightGallery for the overlay. Fixture: <a href="/data/smoke/gallery.json"><code>/data/smoke/gallery.json</code></a>
 — three placehold.co images.</p>
</blockquote>
<h2 id="1-a-single-gallery">1. A single gallery</h2>

  <link
    rel="stylesheet"
    type="text/css"
    href="https://cdn.jsdmirror.com/npm/justifiedGallery@3.8.1/dist/css/justifiedGallery.min.css"
  />
  <link
    rel="stylesheet"
    type="text/css"
    href="https://cdn.jsdmirror.com/npm/lightgallery@2.9.0/css/lightgallery-bundle.min.css"
  />
  <link
    rel="stylesheet"
    type="text/css"
    href="/css/_shortcodes/gallery.css"
  />


<div
  class="shortcode-gallery"
  shortcode="gallery"
  id="gallery-1"
  data="/data/smoke/gallery.json"
></div>

<h2 id="self-check-list">Self-check list</h2>
<ul>
<li><input disabled="" type="checkbox"> Browser Network panel: <code>/data/smoke/gallery.json</code> returns 200</li>
<li><input disabled="" type="checkbox"> CDN injection: jQuery / justifiedGallery / lightGallery (+ thumbnail / zoom plugins) all load</li>
<li><input disabled="" type="checkbox"> DOM: <code>#gallery-1</code> is replaced at runtime with three <code>&lt;a&gt;&lt;img&gt;&lt;/a&gt;</code> items, laid out on one row by justifiedGallery</li>
<li><input disabled="" type="checkbox"> Clicking any thumbnail opens the lightGallery overlay with arrow navigation across all three images</li>
<li><input disabled="" type="checkbox"> The overlay caption shows the <code>subHtml</code> block (&ldquo;Smoke fixture #1/2/3&rdquo;)</li>
<li><input disabled="" type="checkbox"> Background and controls are readable in dark mode</li>
<li><input disabled="" type="checkbox"> No <code>lightGallery</code> / <code>justifiedGallery</code> errors in the console</li>
</ul>
]]></content:encoded></item><item><title>T11h Include Smoke Test</title><link>https://me.125520.xyz/en/t11h-include-smoke/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11h-include-smoke/</guid><description>Integration check for the include shortcode — readFile + safeHTML pipeline.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11h. The include shortcode runs <code>readFile | safeHTML</code>, dropping a project-root-relative file&rsquo;s contents into the page as raw HTML. Fixture: <code>assets/snippets/hello.html</code> — a small heading / list / link snippet.</p>
</blockquote>
<h2 id="1-including-an-html-snippet">1. Including an HTML snippet</h2>
<p>The block below is pulled in via the include shortcode:</p>


<section class="include-fixture-demo">
  <h3>Inkstone include fixture</h3>
  <p>This block was loaded from <code>assets/snippets/hello.html</code> via the <code>include</code> shortcode.</p>
  <ul>
    <li>Heading rendered as <code>&lt;h3&gt;</code></li>
    <li>Inline code rendered as <code>&lt;code&gt;</code></li>
    <li>External anchor: <a href="https://example.com" target="_blank" rel="noopener">example.com</a></li>
  </ul>
</section>


<h2 id="self-check-list">Self-check list</h2>
<ul>
<li><input disabled="" type="checkbox"> The block above renders as HTML — <strong>not</strong> as source (no visible <code>&lt;section&gt;</code> tag characters)</li>
<li><input disabled="" type="checkbox"> The &ldquo;Inkstone include fixture&rdquo; heading is rendered as <code>&lt;h3&gt;</code></li>
<li><input disabled="" type="checkbox"> The three list items render as <code>&lt;li&gt;</code>, with inner <code>&lt;code&gt;</code> adopting the site inline-code style</li>
<li><input disabled="" type="checkbox"> The &ldquo;example.com&rdquo; link in the final item is a real link, with <code>target=&quot;_blank&quot;</code> on hover</li>
<li><input disabled="" type="checkbox"> Hugo build emits no readFile error</li>
</ul>
]]></content:encoded></item><item><title>T11i Include-Code Smoke Test</title><link>https://me.125520.xyz/en/t11i-include-code-smoke/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11i-include-code-smoke/</guid><description>Integration check for the include-code shortcode — readFile + Chroma highlight + language switching.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11i. The include-code shortcode reads a file via <code>readFile</code>, wraps it in a fenced code block, and runs it through <code>markdownify</code> so Chroma applies syntax highlighting. This page exercises two languages — python and yaml — switched via the <code>language=</code> parameter.</p>
</blockquote>
<h2 id="1-python-assetssnippetshellopy">1. Python (<code>assets/snippets/hello.py</code>)</h2>


<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">gcd</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;Return the greatest common divisor of a and b.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="n">b</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span> <span class="o">%</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">gcd</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">18</span><span class="p">))</span>
</span></span></code></pre></div>

<h2 id="2-yaml-assetssnippetsconfigyaml">2. YAML (<code>assets/snippets/config.yaml</code>)</h2>


<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">server</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="m">0.0.0.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="m">8080</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">logging</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">level</span><span class="p">:</span><span class="w"> </span><span class="l">info</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">format</span><span class="p">:</span><span class="w"> </span><span class="l">json</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">features</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">search</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">rss</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="l">sitemap</span><span class="w">
</span></span></span></code></pre></div>

<h2 id="self-check-list">Self-check list</h2>
<ul>
<li><input disabled="" type="checkbox"> Both blocks render as <code>&lt;pre&gt;&lt;code class=&quot;language-...&quot;&gt;</code> rather than as raw source</li>
<li><input disabled="" type="checkbox"> Python block: keywords like <code>def</code> / <code>if __name__</code> are colored by Chroma; docstring is colored too</li>
<li><input disabled="" type="checkbox"> YAML block: keys, strings, and numbers are colored per YAML rules (no fallback to plain text)</li>
<li><input disabled="" type="checkbox"> Line-height / font-size / background match every other fenced code block on the site</li>
<li><input disabled="" type="checkbox"> Both blocks remain readable in dark mode (syntax / background contrast holds)</li>
<li><input disabled="" type="checkbox"> Hugo build emits no readFile error</li>
</ul>
]]></content:encoded></item><item><title>T11d Code Tab Switching Smoke Test</title><link>https://me.125520.xyz/en/t11d-code-tabs-demo/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11d-code-tabs-demo/</guid><description>tab + highlight / fenced code combinations: cross-platform commands, multi-language samples, multi-format configs.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11d. Demonstrates the three common scenarios where the <code>tab</code> shortcode combines with code blocks.
If switching tabs does not switch the code block, the <code>:checked+label+.shortcode-tab-item</code> selector in <code>tab.css</code> isn&rsquo;t taking effect.</p>
</blockquote>
<h2 id="1-cross-platform-command-switching-macos--windows--linux">1. Cross-platform command switching (macOS / Windows / Linux)</h2>
<p>The most common usage — same goal, different shells, different commands.</p>

  <link rel="stylesheet" type="text/css" href="/css/_shortcodes/tab.css" />


<div class="shortcode-tab" style="justify-content: center;">
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304483899-0"
      value="🍎 macOS"
      name="1778163304483899" checked="checked" 
    />
    <label for="1778163304483899-0">🍎 macOS</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">podman compose <span class="nb">exec</span> openclaw-gateway <span class="se">\
</span></span></span><span class="line"><span class="cl">  node dist/index.js channels login --channel feishu
</span></span></code></pre></div>
    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304483899-1"
      value="🪟 Windows"
      name="1778163304483899"
    />
    <label for="1778163304483899-1">🪟 Windows</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="n">podman</span> <span class="n">compose</span> <span class="n">exec</span> <span class="nb">openclaw-gateway</span> <span class="p">`</span>
</span></span><span class="line"><span class="cl">  <span class="n">node</span> <span class="n">dist</span><span class="p">/</span><span class="n">index</span><span class="p">.</span><span class="py">js</span> <span class="n">channels</span> <span class="n">login</span> <span class="p">-</span><span class="n">-channel</span> <span class="n">feishu</span>
</span></span></code></pre></div>
    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304483899-2"
      value="🐧 Linux"
      name="1778163304483899"
    />
    <label for="1778163304483899-2">🐧 Linux</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">sudo podman compose <span class="nb">exec</span> openclaw-gateway <span class="se">\
</span></span></span><span class="line"><span class="cl">  node dist/index.js channels login --channel feishu
</span></span></code></pre></div>
    </div>
</div>

<p>Scan the generated QR code with the companion app to continue configuration.</p>
<h2 id="2-multi-language-code-samples-same-algorithm">2. Multi-language code samples (same algorithm)</h2>
<p>Useful for the &ldquo;same concept, different languages&rdquo; explainer pattern.</p>



<div class="shortcode-tab" style="justify-content: center;">
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304487065-0"
      value="Python"
      name="1778163304487065" checked="checked" 
    />
    <label for="1778163304487065-0">Python</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">gcd</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="n">b</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span> <span class="o">%</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span>
</span></span></code></pre></div>
    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304487065-1"
      value="TypeScript"
      name="1778163304487065"
    />
    <label for="1778163304487065-1">TypeScript</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kd">function</span> <span class="nx">gcd</span><span class="p">(</span><span class="nx">a</span>: <span class="kt">number</span><span class="p">,</span> <span class="nx">b</span>: <span class="kt">number</span><span class="p">)</span><span class="o">:</span> <span class="kt">number</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">while</span> <span class="p">(</span><span class="nx">b</span> <span class="o">!==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="p">[</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nx">b</span><span class="p">,</span> <span class="nx">a</span> <span class="o">%</span> <span class="nx">b</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">a</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>
    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304487065-2"
      value="Go"
      name="1778163304487065"
    />
    <label for="1778163304487065-2">Go</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">gcd</span><span class="p">(</span><span class="nx">a</span><span class="p">,</span><span class="w"> </span><span class="nx">b</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">b</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nx">a</span><span class="p">,</span><span class="w"> </span><span class="nx">b</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">b</span><span class="p">,</span><span class="w"> </span><span class="nx">a</span><span class="o">%</span><span class="nx">b</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">a</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div>
    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304487065-3"
      value="Rust"
      name="1778163304487065"
    />
    <label for="1778163304487065-3">Rust</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">gcd</span><span class="p">(</span><span class="k">mut</span><span class="w"> </span><span class="n">a</span>: <span class="kt">u64</span><span class="p">,</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">b</span>: <span class="kt">u64</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="kt">u64</span> <span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">while</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="kd">let</span><span class="w"> </span><span class="n">t</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">b</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="n">b</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">t</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">a</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span></code></pre></div>
    </div>
</div>

<h2 id="3-multi-format-config-switching-yaml--toml--json">3. Multi-format config switching (YAML / TOML / JSON)</h2>
<p>The &ldquo;pick whichever format you like&rdquo; style of config example.</p>



<div class="shortcode-tab" style="justify-content: flex-start;">
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304488428-0"
      value="YAML"
      name="1778163304488428" checked="checked" 
    />
    <label for="1778163304488428-0">YAML</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">server</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="m">0.0.0.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="m">8080</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">channels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">feishu</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">enabled</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span></span></span></code></pre></div>
    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304488428-1"
      value="TOML"
      name="1778163304488428"
    />
    <label for="1778163304488428-1">TOML</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">server</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">host</span> <span class="p">=</span> <span class="s2">&#34;0.0.0.0&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">port</span> <span class="p">=</span> <span class="mi">8080</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[[</span><span class="nx">channels</span><span class="p">]]</span>
</span></span><span class="line"><span class="cl"><span class="nx">name</span> <span class="p">=</span> <span class="s2">&#34;feishu&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">enabled</span> <span class="p">=</span> <span class="kc">true</span>
</span></span></code></pre></div>
    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304488428-2"
      value="JSON"
      name="1778163304488428"
    />
    <label for="1778163304488428-2">JSON</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;server&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;0.0.0.0&#34;</span><span class="p">,</span> <span class="nt">&#34;port&#34;</span><span class="p">:</span> <span class="mi">8080</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;channels&#34;</span><span class="p">:</span> <span class="p">[{</span> <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;feishu&#34;</span><span class="p">,</span> <span class="nt">&#34;enabled&#34;</span><span class="p">:</span> <span class="kc">true</span> <span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>
    </div>
</div>

<h2 id="4-tab--highlight-shortcode-with-title-bar">4. tab + highlight shortcode (with title bar)</h2>
<p>If you want a title bar on the code block (Hugo&rsquo;s <code>highlight</code> shortcode provides one), swap the fenced block for <code>{{&lt; highlight &gt;}}</code>:</p>



<div class="shortcode-tab" style="justify-content: center;">
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304489454-0"
      value="Development"
      name="1778163304489454" checked="checked" 
    />
    <label for="1778163304489454-0">Development</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight-wrapper">
    <div class="highlight-title">
      <span>.env.development</span>
    </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">DATABASE_URL</span><span class="o">=</span>postgres://localhost:5432/inkstone_dev
</span></span><span class="line"><span class="cl"><span class="nv">DEBUG</span><span class="o">=</span><span class="nb">true</span>
</span></span><span class="line"><span class="cl"><span class="nv">LOG_LEVEL</span><span class="o">=</span>debug</span></span></code></pre></div>
</div>

    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304489454-1"
      value="Production"
      name="1778163304489454"
    />
    <label for="1778163304489454-1">Production</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <div class="highlight-wrapper">
    <div class="highlight-title">
      <span>.env.production</span>
    </div>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">DATABASE_URL</span><span class="o">=</span>postgres://prod-db:5432/inkstone
</span></span><span class="line"><span class="cl"><span class="nv">DEBUG</span><span class="o">=</span><span class="nb">false</span>
</span></span><span class="line"><span class="cl"><span class="nv">LOG_LEVEL</span><span class="o">=</span>warn</span></span></code></pre></div>
</div>

    </div>
</div>

<h2 id="self-check-list">Self-check list</h2>
<ul>
<li><input disabled="" type="checkbox"> Tab switch: clicking different labels switches the code block (CSS only, no JS)</li>
<li><input disabled="" type="checkbox"> Active state: the current tab&rsquo;s label has a 2px underline</li>
<li><input disabled="" type="checkbox"> Nesting: both fenced code blocks and <code>{{&lt; highlight &gt;}}</code> render correctly</li>
<li><input disabled="" type="checkbox"> Emoji label: <code>🍎 / 🪟 / 🐧</code> renders correctly</li>
<li><input disabled="" type="checkbox"> <code>position</code> attribute: section 3 uses <code>position=&quot;start&quot;</code>; labels align to the start</li>
<li><input disabled="" type="checkbox"> Dark mode: after switching to dark, the underline color swaps (<code>--color-shortcode-tab-label-bottom</code>)</li>
</ul>
]]></content:encoded></item><item><title>T11a Academic Core Smoke Test</title><link>https://me.125520.xyz/en/t11a-smoke-test/</link><pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11a-smoke-test/</guid><description>Integration check for the mathjax / mermaid / markmap / antv-g2 / pseudocode quintet.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11a. If you see source instead of a rendered figure, the corresponding shortcode isn&rsquo;t wired up.</p>
</blockquote>
<h2 id="1-mathjax">1. MathJax</h2>
<p>Inline: the mass–energy equation \(E = mc^2\).</p>
<p>Display:</p>
<p>$$
\int_{-\infty}^{\infty} e^{-x^2},dx = \sqrt{\pi}
$$</p>
<h2 id="2-mermaid">2. Mermaid</h2>
<pre class="mermaid" data-pagefind-ignore>
  flowchart LR
  A[content] --&gt; B[markup hook]
  B --&gt; C[Page.Store hasMermaid]
  C --&gt; D[scripts.html init]
</pre>

<h2 id="3-markmap">3. Markmap</h2>
<div class="markmap-container" data-pagefind-ignore>
  <div class="markmap">
    <script type="text/template">
      - T11
  - T11a academic core
    - mathjax
    - mermaid
    - markmap
    - antv-g2
    - pseudocode
  - T11b media
  - T11c content tools
    </script>
  </div>
</div>

<h2 id="4-pseudocode">4. Pseudocode</h2>

  <link
    rel="stylesheet"
    type="text/css"
    href="/css/_shortcodes/pseudocode.css"
  />


<div data-pagefind-ignore>
  <pre
    class="shortcode-pseudocode"
    data-indent-size="1.2em"
    data-comment-delimiter="// "
    data-line-number="true"
    data-line-number-punc=":"
    data-no-end="true"
    data-title-prefix="Algorithm"
  >
    
\begin{algorithm}
\caption{Euclid's algorithm (gcd)}
\begin{algorithmic}
\PROCEDURE{Gcd}{$a, b$}
  \WHILE{$b \neq 0$}
    \STATE $t \gets b$
    \STATE $b \gets a \bmod b$
    \STATE $a \gets t$
  \ENDWHILE
  \RETURN $a$
\ENDPROCEDURE
\end{algorithmic}
\end{algorithm}

  </pre>
</div>

<h2 id="5-antv-g2">5. AntV G2</h2>
<p>(antv-g2 needs a data file to be present; this is just a placeholder call. With no <code>script=</code> attribute it skips the actual chart, but the g2 library should still load correctly.)</p>
<h2 id="6-theme-switch-propagation-05-04-theme-broadcast">6. Theme switch propagation (05-04-theme-broadcast)</h2>
<p>After loading this page, click the sidebar &ldquo;Theme&rdquo; button. You should see:</p>
<ul>
<li><input disabled="" type="checkbox"> mermaid flowchart palette flips immediately (neutral ↔ dark), no double-render ghost</li>
<li><input disabled="" type="checkbox"> If a real antv-g2 chart is present, its palette flips immediately</li>
<li><input disabled="" type="checkbox"> After 5 toggles <code>window.antvG2Charts.length</code> does not grow (memory-leak guard)</li>
<li><input disabled="" type="checkbox"> No console errors during the toggle</li>
<li><input disabled="" type="checkbox"> markmap node text / links / code blocks follow the switch (CSS tokens
inherit into <code>&lt;foreignObject&gt;</code>; branch strokes do not follow because of
inline strokes inside the library — known limitation, see
<code>.trellis/spec/frontend/themed-components.md</code> §4)</li>
</ul>
]]></content:encoded></item><item><title>T11b Media Embed Smoke Test</title><link>https://me.125520.xyz/en/t11b-smoke-test/</link><pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11b-smoke-test/</guid><description>Integration check for bilibili / video / youtube / iframe / swiper / image-compare.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11b. If any of iframe / video player / swiper / image-compare fails to appear, the corresponding shortcode isn&rsquo;t wired up.</p>
</blockquote>
<h2 id="1-bilibili">1. Bilibili</h2>

  <div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin: 1em 0; background: var(--color-bg); color-scheme: light dark;"
  >
    <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://player.bilibili.com/player.html?autoplay=0&amp;bvid=BV1uv411q7Mv&amp;danmaku=0&amp;muted=0&amp;poster=1&amp;t=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0; background: var(--color-bg); color-scheme: light dark;" title="Bilibili video"
    ></iframe>
  </div>

<h2 id="2-videojs-html5-video-player">2. Video.js (HTML5 video player)</h2>


<video
  class="video-js vjs-big-play-centered vjs-fluid"
  data-setup='{
    "controls": true,
    "autoplay": false,
    "preload": "auto",
    "loop": false
  }'>
  <source src="https://test-videos.co.uk/vids/bigbuckbunny/mp4/h264/360/Big_Buck_Bunny_360_10s_1MB.mp4" type="video/mp4"></source>
  <p class="vjs-no-js">Please enable JavaScript and use a browser that supports HTML5 video to watch this video</p>
</video>

<h2 id="3-youtube">3. YouTube</h2>

  <div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; margin: 1em 0; background: var(--color-bg); color-scheme: light dark;"
  >
    <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0; background: var(--color-bg); color-scheme: light dark;" title="Demo"
    ></iframe>
  </div>

<h2 id="4-iframe-generic-embed">4. Iframe (generic embed)</h2>

<div
  style="
    position: relative;
    overflow: hidden;
    width: 100%;
    padding-top: 56.25%;
    background: var(--color-bg);
  "
>
    <iframe
      style="
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        width: 100%;
        height: 100%;
        background: var(--color-bg);
        color-scheme: light dark;
      "
      frameborder="0"
      src="https://example.com"
      allowfullscreen="true"
    ></iframe>
</div>

<h2 id="4a-iframe-whitelisted-host-codepen-theme-bridge">4a. Iframe (whitelisted host: CodePen theme bridge)</h2>
<p>After toggling the site to dark mode, this iframe should auto-reload into the dark theme; the very first request should already carry <code>theme-id=dark</code>.
Non-whitelisted hosts (example.com) stay as-is and do not reload.</p>

<div
  style="
    position: relative;
    overflow: hidden;
    width: 100%;
    padding-top: 56.25%;
    background: var(--color-bg);
  "
>
    <iframe
      data-src="https://codepen.io/MrGrigri/embed/XQmWBv?default-tab=result"
      data-theme-bridge
      style="
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        width: 100%;
        height: 100%;
        background: var(--color-bg);
        color-scheme: light dark;
      "
      frameborder="0"
      allowfullscreen="true"
    ></iframe>
    <script>
      (function (el) {
        var HOSTS = [{"match":"codepen.io","param":"theme-id"},{"match":"codesandbox.io","param":"theme"},{"match":"stackblitz.com","param":"theme"},{"match":"replit.com","param":"theme"}];
        var theme = (window.getTheme && window.getTheme()) || 'light';
        try {
          var u = new URL(el.dataset.src);
          var host = HOSTS.find(function (h) { return u.host.indexOf(h.match) !== -1; });
          if (host) u.searchParams.set(host.param, theme === 'dark' ? 'dark' : 'light');
          el.src = u.toString();
        } catch (_) { el.src = el.dataset.src; }
      })(document.currentScript.previousElementSibling);
    </script>
</div>

<h2 id="5-swiper">5. Swiper</h2>
<p>(swiper requires a data file; this is a placeholder to verify that swiper-bundle JS/CSS is injected. A full test needs a real data reference like
<code>assets/data/cn/2020-06-06-bayesian-optimization/active-gp.json</code>, to be added when actual posts are migrated back.)</p>
<h2 id="6-image-compare">6. Image Compare</h2>
<p>(image-compare needs before/after images; this is a placeholder to verify that image-compare-viewer is injected.)</p>

  <link
    rel="stylesheet"
    type="text/css"
    href="https://cdn.jsdmirror.com/npm/image-compare-viewer@1.6.2/dist/image-compare-viewer.min.css"
  />
  <link
    rel="stylesheet"
    type="text/css"
    href="/css/_shortcodes/image-compare.css"
  />


<div class="shortcode-image-compare-container">
  <div
    class="shortcode-image-compare" data-show-labels="true" data-label-before="Before" data-label-after="After" data-large-max-width="100%" data-middle-max-width="100%" data-small-max-width="100%">
    <img src="/test/before.jpg" />
    <img src="/test/after.jpg" />
  </div>
</div>

]]></content:encoded></item><item><title>T11c Content / Tooling Smoke Test</title><link>https://me.125520.xyz/en/t11c-smoke-test/</link><pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate><guid isPermaLink="true">https://me.125520.xyz/en/t11c-smoke-test/</guid><description>Integration check for figure / tab / flex / song / douban-card / copy-to-clipboard / button / details / highlight / admonition.</description><content:encoded><![CDATA[<blockquote>
<p>Rendering verification for T11c. <code>gallery</code> / <code>include</code> / <code>include-code</code> depend on external data/files and are only verified inside real posts.</p>
</blockquote>
<h2 id="1-figure-explicit-shortcode-form">1. Figure (explicit shortcode form)</h2>


<figure
  class="shortcode-figure">
  <img
    class="lazyload"
    data-src="https://placehold.co/600x300"
    alt="placeholder"
    title="Placeholder image (explicit figure shortcode)"
    data-large-max-width="100%"
    data-middle-max-width="100%"
    data-small-max-width="100%"
    data-large-max-height="100%"
    data-middle-max-height="100%"
    data-small-max-height="100%"
  />
    <figcaption>Placeholder image (explicit figure shortcode)</figcaption>
</figure>

<h2 id="2-tab">2. Tab</h2>

  <link rel="stylesheet" type="text/css" href="/css/_shortcodes/tab.css" />


<div class="shortcode-tab" style="justify-content: center;">
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304490370-0"
      value="Item 1"
      name="1778163304490370" checked="checked" 
    />
    <label for="1778163304490370-0">Item 1</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <p>Content of the first tab.</p>

    </div>
    <input
      type="radio"
      class="shortcode-tab-input"
      id="1778163304490370-1"
      value="Item 2"
      name="1778163304490370"
    />
    <label for="1778163304490370-1">Item 2</label>
    <div class="shortcode-tab-item">
      <div style="margin-bottom: var(--spacing-p-margin-y);"></div>
      <p>Content of the second tab.</p>

    </div>
</div>

<h2 id="3-flex">3. Flex</h2>

  <link rel="stylesheet" type="text/css" href="/css/_shortcodes/flex.css" />


<div
  class="shortcode-flex"
  style="
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: space-between;
  align-items: center;
  align-content: center;
  row-gap: 16px;
  column-gap: 16px;"
>
  
  <div
  class="shortcode-flex-item"
  style="
  align-self: auto;
  flex-basis: auto;
  flex-grow: 1;
  flex-shrink: 1;
  order: 0;"
>
  <p>Left</p>

</div>

  <div
  class="shortcode-flex-item"
  style="
  align-self: auto;
  flex-basis: auto;
  flex-grow: 1;
  flex-shrink: 1;
  order: 0;"
>
  <p>Right</p>

</div>


</div>

<h2 id="4-song">4. Song</h2>

  <link
    rel="stylesheet"
    type="text/css"
    href="https://cdn.jsdmirror.com/npm/aplayer@1.10.1/dist/APlayer.min.css"
  />
  <link rel="stylesheet" type="text/css" href="/css/_shortcodes/song.css" />
  <script src="https://cdn.jsdmirror.com/npm/aplayer@1.10.1/dist/APlayer.min.js"></script>
  <script src="https://cdn.jsdmirror.com/npm/meting@2.0.2/dist/Meting.min.js"></script>
  <script>
    window.meting_api = "https:\/\/api.i-meto.com\/meting\/api?server=:server\u0026type=:type\u0026id=:id\u0026auth=:auth\u0026r=:r";
  </script>


<meting-js
  id="22845161" server="netease" type="song">
</meting-js>

<h2 id="5-douban-card">5. Douban Card</h2>

  <link
    rel="stylesheet"
    type="text/css"
    href="/css/_shortcodes/douban-card.css"
  />


<div
  class="shortcode-douban-card shortcode-douban-card-book"
  id="shortcode-douban-card-book-34922183"
>
  <div class="shortcode-douban-card--middle">
    <div class="shortcode-douban-card--title">
      <a href="https://book.douban.com/subject/34922183/" target="_blank">人类群星闪耀时</a>
    </div>
    <div class="shortcode-douban-card--stars-rating">
      <span class="shortcode-douban-card--logo-dou">豆</span>
      <span class="shortcode-douban-card--logo-rating">豆瓣评分</span>
      <div class="shortcode-douban-card--stars shortcode-douban-card--stars-9"></div>
      <span class="shortcode-douban-card--rating">9.0</span>
    </div>
    <div class="shortcode-douban-card--tags">
      历史 / 茨威格
    </div>
    <div class="shortcode-douban-card--summary">
      14 个人类历史的高光时刻。
    </div>
  </div>
  <div class="shortcode-douban-card--right">
    <img src="https://placehold.co/100x150" />
  </div>
</div>

<h2 id="6-copy-to-clipboard">6. Copy to clipboard</h2>

  <link rel="stylesheet" type="text/css" href="/css/_shortcodes/button.css" />

<a class="shortcode-copy-to-clipboard" data-clipboard-text="print(&#34;hello, inkstone&#34;)" data-clipboard-success-message="Copied" data-clipboard-error-message="Copy failed" role="button">Copy this
</a>

<h2 id="7-button">7. Button</h2>

  <link rel="stylesheet" type="text/css" href="/css/_shortcodes/button.css" />

<a class="shortcode-button"href="/posts/"target="_blank"
  role="button">Go to posts list</a>

<h2 id="8-details">8. Details</h2>

<details>
  <summary>
    <span>Click to expand</span>
  </summary>
  <p>This is the collapsed content; click the summary to expand.</p>
</details>

<h2 id="9-highlight-with-title">9. Highlight (with title)</h2>



<div class="highlight-wrapper">
    <div class="highlight-title">
      <span>Example: Euclid&rsquo;s algorithm</span>
    </div>

  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">gcd</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="n">b</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span> <span class="o">%</span> <span class="n">b</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">a</span></span></span></code></pre></div>
</div>

<h2 id="10-admonition">10. Admonition</h2>

  <link
    rel="stylesheet"
    type="text/css"
    href="/css/_shortcodes/admonition.css"
  />
  <div
    class="shortcode-admonition shortcode-admonition-note "
  >
      <div class="shortcode-admonition-title">Reminder</div>
      <div class="shortcode-admonition-content">This is an admonition block. The shortcode-admonition CSS and the callout
CSS remain independent (whether to merge them is a T12 polish decision).</div>
  </div>


  <div
    class="shortcode-admonition shortcode-admonition-warning "
  >
      <div class="shortcode-admonition-content">Foldable admonition: collapsed by default, click to expand.</div>
  </div>

]]></content:encoded></item></channel></rss>