<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Quan Nguyen</title>
        <link>https://qu8n.com</link>
        <description>Quan Nguyen's RSS Feed</description>
        <lastBuildDate>Tue, 07 Apr 2026 21:00:18 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>All rights reserved 2026, Quan Nguyen</copyright>
        <atom:link href="https://qu8n.com/rss.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Tree-sitter migration guide for Neovim 0.12]]></title>
            <link>https://qu8n.com/posts/treesitter-migration-guide-for-nvim-0-12</link>
            <guid isPermaLink="false">https://qu8n.com/posts/treesitter-migration-guide-for-nvim-0-12</guid>
            <pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A quick guide to updating your nvim-treesitter configs for Neovim 0.12.]]></description>
            <content:encoded><![CDATA[<p>Neovim recently updated to 0.12 with major improvements to the built-in LSP client and better terminal handling among <a href="https://gpanders.com/blog/whats-new-in-neovim-0.12/">other nice things</a>.</p>
<p>This update broke my setup: opening Neovim afterwards showed a wall of <code>attempt to call method &#39;start&#39; (a nil value)</code> error from <code>nvim-treesitter</code> along with a full stack trace.</p>
<p>This guide summarizes what I did to get it all working again.</p>
<Callout title="What is treesitter?" type="info">
  Treesitter helps Neovim and other IDEs like VSCode understand the structure of the code. This is then used to power many code editor features like highlighting, indentation, and code folding.

<p>  To nerd out a bit, treesitter works by building a concrete syntax tree (CST) of the source code under the hood. This CST is <em>roughly</em> similar to the DOM tree for HTML, both being structured representations of the underlying text.</p>
<p>  The tree-sitter docs has a cool <a href="https://tree-sitter.github.io/tree-sitter/7-playground.html">playground</a> that lets you see the syntax tree for a piece of code in real time.
</Callout></p>
<h2>What to change in <code>nvim-treesitter</code></h2>
<p>Neovim bundles the treesitter runtime, but most people use the <a href="https://github.com/nvim-treesitter/nvim-treesitter"><code>nvim-treesitter</code></a> plugin to manage parser installation and configuration.</p>
<p>That plugin got a <a href="https://github.com/nvim-treesitter/nvim-treesitter/discussions/7901">full rewrite</a> on a new <code>main</code> branch. The old <code>master</code> branch is frozen and won&#39;t work with Neovim 0.12.</p>
<h3>1. Install the <code>tree-sitter</code> CLI</h3>
<p>The new <code>nvim-treesitter</code> compiles parsers locally and depends on the <a href="https://tree-sitter.github.io/tree-sitter/">tree-sitter CLI</a>. The old version bundled everything. The new one doesn&#39;t so we have to install it manually.</p>
<h3>2. Reinstall the plugin</h3>
<Callout type="warn">
  These code examples reflect my [lazy.nvim](https://github.com/folke/lazy.nvim) plugin manager. Adjust for your plugin manager if you use something else.
</Callout>

<p>The default branch changed from <code>master</code> to <code>main</code>. Update your plugin spec to pull from the new branch:</p>
<pre><code class="language-lua">{
  &#39;nvim-treesitter/nvim-treesitter&#39;,
  branch = &#39;master&#39;, -- [!code --]
  branch = &#39;main&#39;, -- optional as main is default, but I like being explicit // [!code ++]
  ...
},
</code></pre>
<p>Find <code>nvim-treesitter</code> in the lazy.nvim UI, press <code>x</code> to remove the old version, then <code>:Lazy update nvim-treesitter</code> to pull the new <code>main</code> branch.</p>
<h3>3. Fix the module name</h3>
<p>The old config module <code>nvim-treesitter.configs</code> no longer exists. The new plugin exports <code>setup()</code> from the top-level <code>nvim-treesitter</code> module. If you have a <code>main</code> field in your lazy.nvim spec, update it:</p>
<pre><code class="language-lua">main = &#39;nvim-treesitter.configs&#39;, -- [!code --]
main = &#39;nvim-treesitter&#39;, -- [!code ++]
</code></pre>
<h3>4. Enable highlighting and indentation yourself</h3>
<p>The old plugin had a module system where you&#39;d enable highlighting and indentation by passing options to <code>setup()</code>.</p>
<p>The new plugin simplifies the API and just handles parser installation, so we need to enable these features ourselves via a <code>FileType</code> autocmd:</p>
<pre><code class="language-lua">opts = {
  highlight = { enable = true }, -- [!code --]
  indent = { enable = true }, -- [!code --]
  -- ...
},
init = function()
  vim.api.nvim_create_autocmd(&#39;FileType&#39;, { -- [!code ++]
    callback = function() -- [!code ++]
      -- Enable treesitter highlighting and disable regex syntax // [!code ++]
      pcall(vim.treesitter.start) -- [!code ++]
      -- Enable treesitter-based indentation // [!code ++]
      vim.bo.indentexpr = &quot;v:lua.require&#39;nvim-treesitter&#39;.indentexpr()&quot; -- [!code ++]
    end, -- [!code ++]
  }) -- [!code ++]
  -- ...
end,
</code></pre>
<h3>5. Replace <code>ensure_installed</code></h3>
<p><code>ensure_installed</code> is no longer a config option. You call the install API yourself instead.</p>
<p>Here&#39;s an <code>init</code> callback that diffs against already-installed parsers so it doesn&#39;t reinstall everything on every startup:</p>
<pre><code class="language-lua">init = function()
  local ensureInstalled = {
    &#39;lua&#39;, &#39;python&#39;, &#39;typescript&#39;,
    -- ... your parsers
  }
  local alreadyInstalled = require(&#39;nvim-treesitter.config&#39;).get_installed()
  local parsersToInstall = vim.iter(ensureInstalled)
    :filter(function(parser)
      return not vim.tbl_contains(alreadyInstalled, parser)
    end)
    :totable()
  require(&#39;nvim-treesitter&#39;).install(parsersToInstall)
end,
</code></pre>
<h2>Textobjects (optional)</h2>
<p>If you use <a href="https://github.com/nvim-treesitter/nvim-treesitter-textobjects"><code>nvim-treesitter-textobjects</code></a>, same story. You need its <code>main</code> branch too:</p>
<pre><code class="language-lua">{
  &#39;nvim-treesitter/nvim-treesitter-textobjects&#39;,
  branch = &#39;master&#39;, -- [!code --]
  branch = &#39;main&#39;, -- [!code ++]
  ...
}
</code></pre>
<h2>Last steps</h2>
<ol>
<li><code>:Lazy update nvim-treesitter</code> to pull the new <code>main</code> branch</li>
<li><code>:TSUninstall all</code> to remove old parsers compiled by the <code>master</code> branch</li>
<li>Restart Neovim</li>
<li><code>:TSUpdate</code> to rebuild parsers with the new compiler</li>
<li><code>:checkhealth nvim-treesitter</code> to make sure everything&#39;s wired up</li>
</ol>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Write anyway]]></title>
            <link>https://qu8n.com/posts/why-you-should-write-online</link>
            <guid isPermaLink="false">https://qu8n.com/posts/why-you-should-write-online</guid>
            <pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[AI can write for us now. That's exactly why we should write ourselves.]]></description>
            <content:encoded><![CDATA[<p>With recent AI advances, I feel more strongly than ever that we all should write, specifically with no or minimal AI assistance.</p>
<h2>Writing to think</h2>
<blockquote>
<p>Writing is thinking. To write well is to think clearly.</p>
<p>If people cannot write well, they cannot think well; and if they cannot think well, others will do their thinking for them.</p>
</blockquote>
<p>I started writing more this year, and its biggest benefit so far has been the mental clarity. Putting my jumbled thoughts down into words has forced them to be clearer and more structured.</p>
<p>The writing process is iterative:</p>
<p><Mermaid
  chart="flowchart TD
    A[jumbled thoughts] --> B[write]
    B --> C[get stuck]
    C --> D[discover gap]
    D --> E[think harder]
    E --> B
    E -.->|until nothing is fuzzy| F([done])"
/></p>
<p>If you&#39;re scared of sharing your writing online, note that sharing is <strong>completely optional</strong>. We don&#39;t all have to be influencers. Write for yourself. Write a journal entry, write a technical post, write a romance novel, write about something you don&#39;t know much about. Most importantly, write whatever you want.</p>
<p>And if you happen to think that your writing could be helpful for others, share it.</p>
<h2>Writing to do <a href="https://paulgraham.com/greatwork.html">great work</a></h2>
<p>We talk a lot about writing well for AI (i.e., prompt engineering) but not enough about writing well for humans.</p>
<p>The most advanced models are still <a href="https://substack.com/@alifeengineered/note/c-210898532">terrible at writing</a>, at least when it comes to writing like an actual human. This is our opportunity: I&#39;m positive that being able to write well will help one&#39;s career, especially as AI-written content becomes more ubiquitous.</p>
<p>Think about the last time you read an obviously AI-generated post. It felt icky, didn&#39;t it? I hate it, and I know people hate it, too.</p>
<p>So when you write at work -- an email, Slack message, or presentation -- having people actually read and want to read your writing means your voice will be heard and your organizational influence will increase.</p>
<h2>Writing to connect</h2>
<p>Online discourse in tech is an echo chamber, and it loves fear- and hype-driven topics. For example, this is what shows up on <a href="https://techcrunch.com/">TechCrunch</a>&#39;s homepage right now as I&#39;m writing this post:</p>
<img alt="The TechCrunch homepage" src={__img0} placeholder="blur" />

<p>11 AI or AI-related articles in this screenshot. They covered half of the &quot;Latest News&quot; articles and almost all the &quot;Most Popular&quot; articles. There is nothing wrong with covering AI, but this makes me feel like they&#39;re shoving AI down my throat.</p>
<p>Now let me introduce you to my oasis, my RSS feed:</p>
<img alt="My RSS feed" src={__img1} placeholder="blur" />

<p>This is a personal newsfeed of writings from my favorite humans like <a href="https://vickiboykis.com/">Vicky Boykis</a>, <a href="https://mitchellh.com/writing">Mitchell Hashimoto</a>, <a href="https://weakty.com/">Ty Sloane</a>, and <a href="https://www.seangoedecke.com/">Sean Goedecke</a>.</p>
<p>Sure, they probably all have written about AI, too, but what sets them apart is each person&#39;s &quot;voice&quot;. Each has a distinct way of conveying their thoughts in words, each making me feel something different as a reader. I feel a sense of closeness and connectedness to each writer in a way that AI-generated content doesn&#39;t.</p>
<p>The content that we see online will be more and more AI-generated. AI slop is getting built on top of slop on top of more slop, and VCs are talking about an &quot;agent-first&quot; internet.</p>
<p>What&#39;s going to happen to our internet? My ideal version of the internet exists to connect us, to show us the humanity in each other, and I don&#39;t think that AI can do that in a genuine way. I&#39;m afraid we&#39;d lose the internet as we know it if we don&#39;t share our voices online at all.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Software engineers can no longer neglect their soft skills]]></title>
            <link>https://qu8n.com/posts/most-important-software-engineering-skill-2026</link>
            <guid isPermaLink="false">https://qu8n.com/posts/most-important-software-engineering-skill-2026</guid>
            <pubDate>Tue, 06 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The bottleneck has shifted from implementation to specification.]]></description>
            <content:encoded><![CDATA[<p>import { EditSection } from &#39;@/components/edit-section&#39;;</p>
<p>Starting in 2026, communication has become the most important skill for software engineers.</p>
<p>It&#39;s not writing code, system designs, or having estoric knowledge of a programming language (i.e., Rust).</p>
<p>AI coding agents have gotten <a href="https://x.com/bcherny/status/2004897269674639461">very, very good</a>. A year ago, I&#39;d reach out to Cursor hesitantly for MVPs or quick fixes. Today, I use Claude Code for almost all non-trivial programming tasks and have spent $500+ on it just last December.</p>
<p>AI talks online revolve much around the hard skils. Initially it was prompt tricks to accomplish X, then the best MCPs for Y, and so on. But with Opus 4.5, using vanilla Claude Code gets you 80% there. Even in the age of AI, the 80/20 rule still applies. So, what should engineers focus on?</p>
<p>One thing with coding agents is that the better the spec, the more in line they will be with the technical and business requirements. But getting a good spec is hard.</p>
<p>In real life, tickets rarely contain all the requirements. To do so, you might need to:</p>
<ul>
<li>Ask questions that reveal assumptions people didn&#39;t know they had</li>
<li>Facilite trade-off discussions</li>
<li>Push back on scope without burning bridges</li>
<li>Make calls on things nobody thought to specify</li>
</ul>
<p>Doing these things well used to be optional for individual contributors. Certain teams would enable engineers to thrive being an average communicator but excellent coder. Now, the non-coding parts are becoming a non-negotiable.</p>
<p>Software engineers are problem solvers. We believe that every problem has a solution, a &quot;best practice&quot;. But working with people is messy.</p>
<p><del>Un</del>fortunately, we won&#39;t be able to AI our way into better communication skills. Good communication requires empathy, and we can all use a little more of that in today&#39;s landscape.</p>
<EditSection>
  Edit: This post got some traction on Hacker News. See the discussion [here](https://news.ycombinator.com/item?id=46667572).
</EditSection>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Running Claude Code from my phone]]></title>
            <link>https://qu8n.com/posts/running-claude-code-from-my-phone</link>
            <guid isPermaLink="false">https://qu8n.com/posts/running-claude-code-from-my-phone</guid>
            <pubDate>Mon, 22 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[A guide to controlling Claude Code running on your laptop from your phone over SSH using Termius, Tailscale, and tmux.]]></description>
            <content:encoded><![CDATA[<p>import { Info } from &#39;lucide-react&#39;;
import { YacineTweet } from &#39;./yacine-tweet.tsx&#39;;</p>
<img alt="hero" src={__img0} placeholder="blur" />

<h2>Introduction</h2>
<p>When I run Claude Code on a larger task, I often end up waiting on it while wanting to step away: coffee, a meeting, or a walk. I didn’t want to keep checking my laptop just to see whether it needed input or had finished.</p>
<p>Over the past month, I’ve been using a simple setup that lets me:</p>
<ul>
<li>keep Claude Code running on my Mac,</li>
<li>attach to the same session from my phone,</li>
<li>and get notified when it needs attention.</li>
</ul>
<YacineTweet />

<p>Mine is a simple workflow with SSH, tmux, and a couple of notification hooks, but it’s been reliable enough that I now use it almost daily.</p>
<p>This post documents my personal setup. If you’re on different devices or platforms, most of the ideas still apply.</p>
<h2>Prerequisites</h2>
<p>At a high level, the idea is:</p>
<ul>
<li>Claude Code runs on my Mac.</li>
<li>tmux keeps the session alive.</li>
<li>my phone SSHs in over Tailscale.</li>
<li>Claude Code hooks send notifications when it stops or needs input.</li>
</ul>
<p>Install the following tools on your Mac and/or iPhone:</p>
<table>
<thead>
<tr>
<th>Tool to install</th>
<th>Mac</th>
<th>iPhone</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><a href="https://claude.com/product/claude-code">Claude Code</a></td>
<td>✅</td>
<td></td>
<td>Anthropic’s AI coding assistant</td>
</tr>
<tr>
<td><a href="https://github.com/tmux/tmux/wiki">tmux</a></td>
<td>✅</td>
<td></td>
<td>Access the same Claude Code session on your Mac and iPhone</td>
</tr>
<tr>
<td><a href="https://tailscale.com/download">Tailscale</a></td>
<td>✅</td>
<td>✅</td>
<td>Secure the SSH connection between your Mac and iPhone</td>
</tr>
<tr>
<td><a href="https://termius.com">Termius</a></td>
<td></td>
<td>✅</td>
<td>SSH client for your iPhone to connect to your Mac</td>
</tr>
<tr>
<td><a href="https://github.com/julienXX/terminal-notifier#download">terminal-notifier</a></td>
<td>✅</td>
<td></td>
<td>Get notifications on your Mac on Claude Code events</td>
</tr>
<tr>
<td><a href="https://ntfy.sh/">ntfy</a></td>
<td></td>
<td>✅</td>
<td>Get push notifications on your iPhone on Claude Code events</td>
</tr>
</tbody></table>
<p>I chose this combination of tools based on my familiarity with them (like tmux), cost (Termius and ntfy have generous free tiers), and ease of use (Tailscale).</p>
<p>I also wanted to (1) share the same Claude Code sessions between devices and (2) get notified on both devices when Claude Code needs my attention.</p>
<h2>Enable Remote Login on your Mac</h2>
<p><em>This step allows your Mac to accept SSH connections from other devices, enabling your iPhone to connect to it remotely.</em></p>
<ol>
<li>On your Mac, choose Apple menu , then click System Settings.</li>
<li>Click General ⚙️ in the sidebar, then click Sharing. (You may need to scroll down.)</li>
<li>Click <Info className="inline h-4 w-4" /> next to Remote Login.</li>
<li>Turn on Remote Login.</li>
<li>Turn on &quot;Allow full disk access for remote users&quot;.</li>
</ol>
<h2>Set up Tailscale</h2>
<p><em>Tailscale creates a VPN between your devices, protecting the SSH connection between your Mac and iPhone.</em></p>
<ol>
<li>Sign in with the same Tailscale account on both your Mac and iPhone.</li>
<li>Turn on Tailscale on both devices.</li>
<li>On your Mac, click on the Tailscale menu bar icon.</li>
<li>Note your Mac&#39;s Tailscale IP address (it will look like <code>100.x.x.x</code>). You&#39;ll use this IP address in the next step.</li>
</ol>
<h2>Set up Termius</h2>
<p><em>Termius is an SSH client that lets your iPhone connect to your Mac&#39;s terminal, allowing you to control Claude Code remotely.</em></p>
<h3>Generate a Termius SSH key</h3>
<ol>
<li>On your iPhone, open Termius.</li>
<li>Go to the &quot;Keychain&quot;, and tap the add button (+), then &quot;Generate Key&quot;.</li>
<li>Tap &quot;Save&quot; to create the key with default settings.</li>
<li>Tap on the newly created key, then export icon, and then &quot;Copy Public Key&quot;. We&#39;ll use this in the next step.</li>
</ol>
<h3>Add the Termius key to Mac</h3>
<ol>
<li><p>Return to your Mac and create the <code>~/.ssh/authorized_keys</code> file if it doesn&#39;t exist:</p>
<pre><code class="language-bash"> mkdir -p ~/.ssh &amp;&amp; touch ~/.ssh/authorized_keys
</code></pre>
</li>
<li><p>Ensure proper permissions:</p>
<pre><code class="language-bash"> chmod 700 ~/.ssh &amp;&amp; chmod 600 ~/.ssh/authorized_keys
</code></pre>
</li>
<li><p>Append the copied public key from Termius to the end of the <code>authorized_keys</code> file:</p>
<pre><code class="language-bash">echo &quot;REPLACE_THIS_WITH_YOUR_TERMIUS_PUBLIC_KEY&quot; &gt;&gt; ~/.ssh/authorized_keys
</code></pre>
<Callout>
  Your Termius public key should look something like "

<p>  <code>ssh-ed25519 AAAA... Generated By Termius</code></p>
<p>  &quot;.</p>
</Callout></li>
</ol>
<h3>Add your Mac as a Host in Termius</h3>
<ol>
<li>Return to Termius on your iPhone.</li>
<li>Go to &quot;Hosts&quot;, and tap the add button (+), then &quot;New Host&quot;.</li>
<li>Enter the following details and leave other fields as default:<ul>
<li>&quot;Label&quot;: Any custom identifier for your Mac (e.g., &quot;My Personal Mac&quot;).</li>
<li>&quot;IP or Hostname&quot;: Enter the Mac&#39;s Tailscale IP noted earlier (e.g., <code>100.123.45.67</code>).</li>
<li>&quot;Username&quot;: Your Mac login username.</li>
<li>&quot;SSH.id, Key, Certificate, FIDO2&quot;: Select the SSH key generated earlier.</li>
</ul>
</li>
<li>Tap &quot;Save&quot;, then &quot;Connect&quot;.</li>
</ol>
<h2>Share the same Claude Code session</h2>
<p><em>tmux lets us access the same terminal session from both the Mac and iPhone. You can start a Claude Code session on your Mac, then seamlessly switch to your iPhone to continue from exactly where you left off and vice versa.</em></p>
<p>Before connecting from your iPhone, create a tmux session on your Mac:</p>
<pre><code class="language-bash">tmux new -s session_name
</code></pre>
<p>Next, navigate to your code directory and start Claude Code:</p>
<pre><code class="language-bash">claude
</code></pre>
<p>You can now work normally on your Mac. The tmux session persists in the background even if you close the terminal window.</p>
<p>Next, switch back to Termius on your iPhone and run:</p>
<pre><code class="language-bash">tmux attach -t session_name
</code></pre>
<p>You&#39;ll see the exact same session that&#39;s running on your Mac, with all history and state intact.</p>
<p>Both devices can now view and control the same Claude Code session simultaneously. Any commands you type on your iPhone will appear on your Mac in real-time, and vice versa.</p>
<Callout title="Tip" type="info">
  New to `tmux`? Here are some handy commands:

<ul>
<li>Create a new session: <code>tmux new -s session_name</code></li>
<li>Attach to a session: <code>tmux attach -t session_name</code></li>
<li>Detach from session: <code>Ctrl + b</code>, then <code>d</code></li>
<li>Create a new window (tab) within a session: <code>Ctrl + b</code>, then <code>c</code></li>
<li>List sessions: <code>tmux ls</code></li>
<li>Kill session: <code>tmux kill-session -t session_name</code></li>
<li>See more in this <a href="https://tmuxcheatsheet.com/">cheat sheet</a></Callout></li>
</ul>
<h2>Set up notifications</h2>
<p><em>Get notified on both your Mac and iPhone when Claude Code completes tasks or needs your attention.</em></p>
<h3>Subscribe to a topic in ntfy</h3>
<p><em>ntfy is a simple push notification service that works via HTTP. We&#39;ll use it to send notifications from Claude Code running on your Mac to your iPhone.</em></p>
<ol>
<li>On your iPhone, open the ntfy app.</li>
<li>Tap the &quot;+&quot; button to add a new subscription.</li>
<li>Enter a unique topic name (e.g., <code>my-topic</code>) and tap &quot;Subscribe&quot;. If you use ntfy without sign-up, the topic is essentially a password, so pick something that&#39;s not easily guessable. If you purchase ntfy Pro, you can reserve topic names instead.</li>
</ol>
<h3>Configure Claude Code hooks</h3>
<p><em>With <a href="https://code.claude.com/docs/en/hooks-guide">Claude Code hooks</a>, we can trigger custom commands when certain events occur. We&#39;ll set up hooks to send notifications when Claude Code needs input and when it finishes working.</em></p>
<ol>
<li>Add the following to your global Claude Code settings:</li>
</ol>
<pre><code class="language-json">{
  &quot;hooks&quot;: {
    &quot;Notification&quot;: [
      {
        &quot;matcher&quot;: &quot;&quot;,
        &quot;hooks&quot;: [
          {
            &quot;type&quot;: &quot;command&quot;,
            &quot;command&quot;: &quot;terminal-notifier -title \&quot;🔔 Claude Code\&quot; -message \&quot;I need your input\&quot; -sound default -activate &#39;com.googlecode.iterm2&#39; &amp;&amp; curl -d \&quot;🔔 Claude Code: I need your input\&quot; ntfy.sh/my-topic&quot;
          }
        ]
      }
    ],
    &quot;Stop&quot;: [
      {
        &quot;matcher&quot;: &quot;&quot;,
        &quot;hooks&quot;: [
          {
            &quot;type&quot;: &quot;command&quot;,
            &quot;command&quot;: &quot;terminal-notifier -title \&quot;✅ Claude Code\&quot; -message \&quot;I&#39;m done!\&quot; -sound default -activate &#39;com.googlecode.iterm2&#39; &amp;&amp; curl -d \&quot;✅ Claude Code: I&#39;m done!\&quot; ntfy.sh/my-topic&quot;
          }
        ]
      }
    ]
  },
}
</code></pre>
<ol start="2">
<li>Replace <code>my-topic</code> in the <code>curl</code> commands with the topic name you subscribed to in ntfy.</li>
<li>I use <a href="https://iterm2.com/">iTerm2</a> as my terminal app. If you use a different one, replace <code>&#39;com.googlecode.iterm2&#39;</code> with the appropriate bundle identifier obtained from running <code>osascript -e &#39;id of app &quot;Insert app name&quot;&#39;</code>.</li>
<li>The <code>command</code> does two things: (1) send a notification to your Mac using <code>terminal-notifier</code>, and (2) send a push notification to your iPhone using <code>curl</code> to post to your subscribed ntfy topic. If you only want to be notified on one device, you can remove the other part of the command.</li>
<li>When you&#39;re done, save the settings file and restart Claude Code to apply the new settings.</li>
</ol>
<h2>Reflections</h2>
<p>The biggest win isn’t coding from my phone. It’s not feeling glued to my desk while Claude works. I can walk away then engage when there’s something to do.</p>
<p>But this setup isn&#39;t perfect:</p>
<ul>
<li>Typing on the phone feels clunky for anything more than a quick response, although I suspect I could get faster with practice (see <a href="https://www.reddit.com/r/programming/comments/1hay1z3/developer_wrote_25k_lines_of_neovim_plugin_code/">this NeoVim plugin author</a> who wrote 25K+ lines of code on his phone).</li>
<li>I&#39;m usually in front of my laptop, so the phone notifications are often more distracting than helpful. I ended up disabling the ntfy notifications for now. What would be nice is more granular control over when and how I&#39;m notified.</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Implementing Google SSO in Rails 7]]></title>
            <link>https://qu8n.com/posts/implementing-google-sso-in-rails-7</link>
            <guid isPermaLink="false">https://qu8n.com/posts/implementing-google-sso-in-rails-7</guid>
            <pubDate>Mon, 11 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[This article covers the minimum needed to install Google SSO with Devise in a Ruby on Rails 7 app.]]></description>
            <content:encoded><![CDATA[<p>This is an external post. View it <a href="https://medium.com/dev-genius/how-to-add-google-sign-in-sso-with-devise-to-a-ruby-on-rails-7-app-6d8c5ef7641b">here</a>.</p>
]]></content:encoded>
        </item>
    </channel>
</rss>