<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator>
  <link href="https://mikemcquaid.com/all.xml" rel="self" type="application/atom+xml" />
  <link href="https://mikemcquaid.com/" rel="alternate" type="text/html" />
  <updated>2026-07-19T15:20:01+00:00</updated>
  <id>https://mikemcquaid.com/all.xml</id>

  
  

  <title type="html">Mike McQuaid</title>
  <subtitle>CTPO and Homebrew Project Leader</subtitle>
  <author>
    <name>Mike McQuaid</name>
    
      <email>mike@mikemcquaid.com</email>
    
    
      <uri>https://mikemcquaid.com</uri>
    
  </author>

  
  

  

  
  
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>In Memory of Jason Rudolph</title>
      <link href="https://mikemcquaid.com/in-memory-of-jason-rudolph/" rel="alternate" type="text/html" title="In Memory of Jason Rudolph" />
      
      <published>2026-07-17T00:00:00+00:00</published>
      <updated>2026-07-17T00:00:00+00:00</updated>
      <id>https://mikemcquaid.com/in-memory-of-jason-rudolph/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/in-memory-of-jason-rudolph/"><![CDATA[<p>My friend and former GitHub coworker <a href="https://obits.endswellfuneralhome.com/jason-rudolph">Jason Rudolph died in May 2026</a>.</p>

<p>With the consent of his family, I’m writing about some of my memories of Jason.</p>

<h2 id="platform">Platform</h2>

<p>I first properly (and in meatspace) met Jason when I joined GitHub’s “Platform” team.
That team was a few (unreasonably excellent) engineers who maintained and improved GitHub’s API.
As almost all features ended up touching the API in some way, the role could have easily become a gatekeeping one.
Instead, Jason turned it into primarily an educational one.</p>

<p>Jason didn’t really say no to people.
He would take (sometimes huge) amounts of time and effort explaining and teaching them how and why to do things a better way.</p>

<p>This didn’t just extend to GitHub’s API but also basic things like language.
I remember the first time I incorrectly used the word “less” rather than “fewer”.
Jason delicately and politely contradicted me and explained the difference and how to remember it:</p>

<blockquote>
  <p>fewer are countable items, less is for quantities</p>
</blockquote>

<p>What was so memorable (I think of Jason almost every time I say “fewer”) about this interaction was that he did what I had previously considered impossible.
He gave unsolicited feedback in a way that made clear that he really cared about excellence and helping me achieve it.
As someone who didn’t love unsolicited feedback at the time, he also did it in an incredibly kind, sensitive and gentle way.</p>

<h2 id="emails">Emails</h2>

<p>Another great Jasonism I have quoted many times:</p>

<blockquote>
  <p>Checking your emails is not your job. Doing your job may require checking your emails.</p>
</blockquote>

<p>Email is somewhat irrelevant here but it can be extended more widely to almost anything done by engineers:</p>

<ul>
  <li>writing code</li>
  <li>testing</li>
  <li>project planning</li>
</ul>

<p>This came on the back of conversations about “Inbox Zero” and other email methodologies.</p>

<p>It was also counterintuitive to me at the time because Jason was so organised and efficient. 
This was a lesson (that took me too long to learn) about efficiency.
Efficiency is not about doing everything quickly; it’s about doing the right things steadily.</p>

<h2 id="testing">Testing</h2>

<p>Jason was always a strong advocate for excellent automated testing at GitHub.
He
<a href="https://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with-100-test-coverage/">wrote a great series about testing anti-patterns</a>
that is as relevant today as when he wrote it.</p>

<blockquote>
  <p>100% coverage is meaningless without other supporting habits and practices</p>
</blockquote>

<p>Again, Jason did a great job here of taking the “holy grail of testing” (100% coverage) and pointing out why that’s not the actual goal.</p>

<h2 id="dogs">Dogs</h2>

<p>Jason loved his dog, Abby, and died with her at his side.</p>

<p>When my dog, Lucy, was a puppy, I was a rigid adherent to “positive reinforcement only” dog training.
This worked great except for her habit of sitting in front of the TV and barking at us whenever it was on.</p>

<p>Jason, in his usual pragmatism, gently pointed out that he had found:</p>

<blockquote>
  <p>dogs hate mint breath spray</p>
</blockquote>

<p>A few sprays later near Lucy, she stopped barking at us while we watched TV.
To this day, over a decade later, just showing her the spray will stop her barking.</p>

<h2 id="cancer">Cancer</h2>

<p>I don’t really know when Jason was diagnosed.
We last hung out a couple of years ago when he did a world tour seeing a bunch of his friends.
We had a lovely chat in a pub in Edinburgh and chatted about diving, software, GitHub, dogs and lifting.</p>

<p>I briefly wished in hindsight I’d known he was dying but I think I understand it better now.
Our conversation would have probably been pretty different, even if neither of us wanted that.</p>

<p>From the little I know, he planned his final years in the thoughtful, counterintuitive, kind and pragmatic way he seemed to me to approach everything else.</p>

<p>Goodbye Jason.
I’ll miss you.</p>

<hr />

<p>Jason asked that his friends and family donate to <a href="https://www.cholangiocarcinoma.org/donate/">The Cholangiocarcinoma Foundation</a>.
I did and, if you can afford it, please do so too.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Memories of my friend and former GitHub coworker Jason Rudolph, who died in May 2026.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://github.com/jasonrudolph.png" />
        <media:content medium="image" url="https://github.com/jasonrudolph.png" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Join the OSS Resistance with Mike McQuaid</title>
      <link href="https://chrischinchilla.com/podcast/join-the-oss-resistance-with-mike-mcquaid" rel="alternate" type="text/html" title="Join the OSS Resistance with Mike McQuaid" />
      
        <link href="https://mikemcquaid.com/interviews/join-the-oss-resistance-with-mike-mcquaid/" rel="related" type="text/html" title="Join the OSS Resistance with Mike McQuaid" />
      
      <published>2026-06-26T00:00:00+00:00</published>
      <updated>2026-06-26T00:00:00+00:00</updated>
      <id>https://chrischinchilla.com/podcast/join-the-oss-resistance-with-mike-mcquaid</id>
      
      <content type="html" xml:base="https://chrischinchilla.com/podcast/join-the-oss-resistance-with-mike-mcquaid"><![CDATA[<p>Interviewed by The Tech Lounge Podcast.</p>
          <p>Mike McQuaid discusses OSS Resistance: doing small amounts of open source work on company time, the risks involved and why it may help sustainability.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Mike McQuaid discusses OSS Resistance: doing small amounts of open source work on company time, the risks involved and why it may help sustainability.]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Why is Windows 11 so disliked by programmers – and can Microsoft do anything to change things?</title>
      <link href="https://www.itpro.com/software/windows/why-is-windows-11-so-disliked-by-programmers-and-can-microsoft-do-anything-to-change-things" rel="alternate" type="text/html" title="Why is Windows 11 so disliked by programmers – and can Microsoft do anything to change things?" />
      
        <link href="https://mikemcquaid.com/interviews/why-is-windows-11-so-disliked-by-programmers-and-can-microsoft-do-anything-to-change-things/" rel="related" type="text/html" title="Why is Windows 11 so disliked by programmers – and can Microsoft do anything to change things?" />
      
      <published>2026-06-23T00:00:00+00:00</published>
      <updated>2026-06-23T00:00:00+00:00</updated>
      <id>https://www.itpro.com/software/windows/why-is-windows-11-so-disliked-by-programmers-and-can-microsoft-do-anything-to-change-things</id>
      
      <content type="html" xml:base="https://www.itpro.com/software/windows/why-is-windows-11-so-disliked-by-programmers-and-can-microsoft-do-anything-to-change-things"><![CDATA[<p>Interviewed by Keumars Afifi-Sabet on ITPro.</p>
          <p>“Stop trying to overrule my preferences on how to use my computer.”</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[“Stop trying to overrule my preferences on how to use my computer.”]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Make GitHub Actions Do More For You</title>
      <link href="https://mikemcquaid.com/make-github-actions-do-more-for-you/" rel="alternate" type="text/html" title="Make GitHub Actions Do More For You" />
      
        <link href="https://mikemcquaid.com/interviews/why-is-windows-11-so-disliked-by-programmers-and-can-microsoft-do-anything-to-change-things/" rel="related" type="text/html" title="Make GitHub Actions Do More For You" />
      
      <published>2026-06-22T00:00:00+00:00</published>
      <updated>2026-06-22T00:00:00+00:00</updated>
      <id>https://mikemcquaid.com/make-github-actions-do-more-for-you/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/make-github-actions-do-more-for-you/"><![CDATA[<p>Most people just use GitHub Actions to run their tests.
It can do far more: deploy a PR to production before merge, make release processes more robust and automate the boring chores you keep forgetting to do.</p>

<p>Here are a few patterns I’ve used to make my life easier with GitHub Actions.
I’ve done a bunch to <a href="/homebrew-ci-evolution/">evolve Homebrew’s CI over the years</a> so hopefully I can teach you something.</p>

<h2 id="-merge-queues-with-deployments">🚀 Merge Queues with Deployments</h2>

<p>GitHub’s <a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue">Merge Queue</a> was the last big project I led at GitHub so I’m biased towards it.
It provides a queue of one or more pull requests which are stacked, tested and merged together.</p>

<p>At GitHub, we had a “deploy then merge” workflow where PRs would be tested and then deployed to production before being merged.
Most of our customers had a “merge then deploy” workflow where merges to the default branch would then be deployed.
I always liked the GitHub approach but doing it with non-GitHub tooling was a bit tricky.</p>

<p><img src="https://mikemcquaid.com/images/a/make-github-actions-do-more-for-you.png" alt="GitHub merge queue" /></p>

<p>I found a nice way to do it with Merge Queues in Workbrew and <a href="https://getadministrate.com">Administrate</a>.
The GitHub Actions trigger is the <code class="language-plaintext highlighter-rouge">merge_group</code> event: a job that only runs there can deploy the merge commit to production before it is pushed to <code class="language-plaintext highlighter-rouge">main</code> (or: the default branch).
This provides the nice benefit that anything that ends up on your default branch has already been successfully deployed to production.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">on</span><span class="pi">:</span>
  <span class="c1"># The merge queue trigger event</span>
  <span class="na">merge_group</span><span class="pi">:</span>
  <span class="c1"># The usual pull request jobs</span>
  <span class="na">pull_request</span><span class="pi">:</span>
  <span class="c1"># Duplicate push job to keep caches warm (see below)</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">main</span>

<span class="na">concurrency</span><span class="pi">:</span>
  <span class="na">group</span><span class="pi">:</span> <span class="s">${{ github.workflow }}-${{ github.event_name }}${{ github.event.pull_request.number }}</span>
  <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>

<span class="na">permissions</span><span class="pi">:</span>
  <span class="na">contents</span><span class="pi">:</span> <span class="s">read</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">tests</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">persist-credentials</span><span class="pi">:</span> <span class="kc">false</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">script/test</span>

  <span class="na">deploy</span><span class="pi">:</span>
    <span class="c1"># Only deploy from the merge queue, before the merge lands on `main`.</span>
    <span class="na">if</span><span class="pi">:</span> <span class="s">github.event_name == 'merge_group'</span>
    <span class="na">needs</span><span class="pi">:</span> <span class="s">tests</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">environment</span><span class="pi">:</span> <span class="s">production</span>
    <span class="na">concurrency</span><span class="pi">:</span>
      <span class="c1"># Never let two production deploys race each other.</span>
      <span class="na">group</span><span class="pi">:</span> <span class="s">deploy-production</span>
      <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">false</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">persist-credentials</span><span class="pi">:</span> <span class="kc">false</span>
      <span class="pi">-</span> <span class="na">run</span><span class="pi">:</span> <span class="s">script/deploy --production</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">environment: production</code> gets you deployment history, environment protection rules and secrets.
The <code class="language-plaintext highlighter-rouge">concurrency</code> group makes sure two production deploys never occur at once.
Homebrew’s <a href="https://github.com/Homebrew/brew/blob/main/.github/workflows/tests.yml"><code class="language-plaintext highlighter-rouge">tests.yml</code></a> is a real-world example of wiring up <code class="language-plaintext highlighter-rouge">merge_group</code> (without the deploy step).</p>

<p>Some gotchas here:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">merge_group</code> runs read <code class="language-plaintext highlighter-rouge">actions/cache</code> entries but can’t write them.
Only a <code class="language-plaintext highlighter-rouge">push</code> to your default branch populates the cache, which is why <code class="language-plaintext highlighter-rouge">main</code> is in the trigger list above.
Skip any non-<code class="language-plaintext highlighter-rouge">push</code> jobs or steps that aren’t needed to write cache entries so you’re not running steps unnecessarily.</li>
  <li>the merge queue will only wait for <code class="language-plaintext highlighter-rouge">required</code> jobs to be <code class="language-plaintext highlighter-rouge">successful</code> or <code class="language-plaintext highlighter-rouge">skipped</code> before merging.
This means you should think carefully about what jobs should run at PR time, merge group time or both.</li>
  <li>merge queues unfortunately need a paid GitHub organisation plan (so don’t work on personal repositories).</li>
</ul>

<h2 id="️-releasing-inside-github-actions">🏷️ Releasing inside GitHub Actions</h2>

<p>Another thing I’ve found myself wanting to do on a bunch of projects (e.g. Homebrew, Workbrew) is making a GitHub release with a binary built then uploaded by GitHub Actions.
The typical way this is done is to create a release on GitHub, have a GitHub Action build the binary and then upload it to the release.
This is nice when it works but periodically: whoops, something you did since the last release broke the release pipeline.
At this point you have a broken release and tag and the only real way to fix it is to release again.</p>

<p>Some people will delete and recreate a tag when doing this.
Please don’t!
Git really dislikes changing tags and will not update them in local clones like you expect.
Package managers like Homebrew also get confused as to whether this was on purpose or if you got hacked.
Now that GitHub supports immutable tags: enable them to avoid even tempting yourself.</p>

<p>Instead, we can rely on the fact that you can create a tag locally in a Git repository and push it later.
A <code class="language-plaintext highlighter-rouge">workflow_dispatch</code> trigger is really handy here: it gives you a manual “Run workflow” button in the GitHub UI, complete with the inputs you define (like the tag name below) so you can make a release with a few clicks in GitHub and no development environment.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">on</span><span class="pi">:</span>
  <span class="c1"># Manual trigger used to create a new release.</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>
    <span class="na">inputs</span><span class="pi">:</span>
      <span class="na">tag</span><span class="pi">:</span>
        <span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Git</span><span class="nv"> </span><span class="s">tag</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">release"</span>
        <span class="na">required</span><span class="pi">:</span> <span class="kc">true</span>
        <span class="na">type</span><span class="pi">:</span> <span class="s">string</span>
  <span class="c1"># Run a dry run when pushing relevant files to avoid breakage.</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">paths</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">.github/workflows/release.yml</span>

<span class="na">permissions</span><span class="pi">:</span>
  <span class="na">contents</span><span class="pi">:</span> <span class="s">write</span> <span class="c1"># to push the tag and create the release</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">release</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v7</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Create the tag locally</span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">github.event_name == 'workflow_dispatch'</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">TAG</span><span class="pi">:</span> <span class="s">${{ inputs.tag }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">git tag "${TAG}"</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Build the binary</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">script/build</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Create release (dry-run on push)</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ github.token }}</span>
          <span class="na">TAG</span><span class="pi">:</span> <span class="s">${{ inputs.tag }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then</span>
            <span class="s">git push origin "${TAG}"</span>
            <span class="s">gh release create "${TAG}" --generate-notes</span>
          <span class="s">else</span>
            <span class="s"># check permissions without creating anything</span>
            <span class="s">gh release list</span>
          <span class="s">fi</span>
</code></pre></div></div>

<p>This workflow is nice because it tags locally, only tagging on GitHub when the release is successful and everything was built.
This means you can use <code class="language-plaintext highlighter-rouge">git describe</code> to generate your version number and have it match the release tag, even before it was pushed to GitHub.
The dry run mode avoids things being broken accidentally.
It should do everything except for the actual release and upload of the binary.
Homebrew’s <a href="https://github.com/Homebrew/brew/blob/main/.github/workflows/release.yml"><code class="language-plaintext highlighter-rouge">release.yml</code></a> creates the tag locally this way and only uploads once the build and tests have passed.</p>

<h2 id="-local-development-bootstrap">👢 Local Development Bootstrap</h2>

<p>If you have a local development setup using Homebrew on macOS or Linux it is rarely tested as carefully as production code.
Instead have a job that runs your real bootstrap to avoid things being broken for the next person that onboards to your team.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">on</span><span class="pi">:</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">branches</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">main</span>
  <span class="na">pull_request</span><span class="pi">:</span>
  <span class="na">schedule</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s2">"</span><span class="s">0</span><span class="nv"> </span><span class="s">0</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*"</span>

<span class="na">permissions</span><span class="pi">:</span>
  <span class="na">contents</span><span class="pi">:</span> <span class="s">read</span>
  <span class="na">issues</span><span class="pi">:</span> <span class="s">write</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">bootstrap</span><span class="pi">:</span>
    <span class="na">strategy</span><span class="pi">:</span>
      <span class="na">fail-fast</span><span class="pi">:</span> <span class="kc">false</span>
      <span class="na">matrix</span><span class="pi">:</span>
        <span class="na">os</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">macos-latest</span><span class="pi">,</span> <span class="nv">ubuntu-latest</span><span class="pi">]</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">${{ matrix.os }}</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">persist-credentials</span><span class="pi">:</span> <span class="kc">false</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Run the developer onboarding bootstrap script</span>
        <span class="na">id</span><span class="pi">:</span> <span class="s">bootstrap</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">script/bootstrap</span>

      <span class="c1"># Open a tracking issue (one per OS) the first time bootstrap breaks.</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Open an issue on failure</span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">failure() &amp;&amp; steps.bootstrap.outcome == 'failure'</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ github.token }}</span>
          <span class="na">TITLE</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Bootstrap</span><span class="nv"> </span><span class="s">is</span><span class="nv"> </span><span class="s">broken</span><span class="nv"> </span><span class="s">on</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">matrix.os</span><span class="nv"> </span><span class="s">}}"</span>
          <span class="na">URL</span><span class="pi">:</span> <span class="s">${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">gh issue list --state open --search "${TITLE} in:title" | grep -q . ||</span>
            <span class="s">gh issue create --title "${TITLE}" --label bootstrap \</span>
              <span class="s">--body "Bootstrap failed: ${URL}"</span>

      <span class="c1"># Close it again once bootstrap is green.</span>
      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Close the issue on success</span>
        <span class="na">if</span><span class="pi">:</span> <span class="s">success()</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ github.token }}</span>
          <span class="na">TITLE</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Bootstrap</span><span class="nv"> </span><span class="s">is</span><span class="nv"> </span><span class="s">broken</span><span class="nv"> </span><span class="s">on</span><span class="nv"> </span><span class="s">${{</span><span class="nv"> </span><span class="s">matrix.os</span><span class="nv"> </span><span class="s">}}"</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">gh issue list --state open --search "${TITLE} in:title" --json number --jq '.[].number' |</span>
            <span class="s">while read -r number; do</span>
              <span class="s">gh issue close "${number}" --comment "Bootstrap is green again."</span>
            <span class="s">done</span>
</code></pre></div></div>

<h2 id="-autocommits">🔄 Autocommits</h2>

<p>When you’ve got manual jobs you run periodically that update or clean up files, get GitHub Actions to do this for you.
It can regenerate files, check for differences, commit them to a branch and open a pull request.
On reruns, force-push so the PR always reflects the newest version.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">on</span><span class="pi">:</span>
  <span class="na">schedule</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s2">"</span><span class="s">0</span><span class="nv"> </span><span class="s">0</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*"</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>

<span class="na">permissions</span><span class="pi">:</span>
  <span class="na">contents</span><span class="pi">:</span> <span class="s">write</span>
  <span class="na">pull-requests</span><span class="pi">:</span> <span class="s">write</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">update</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v7</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Regenerate the files</span>
        <span class="na">run</span><span class="pi">:</span> <span class="s">script/generate</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Commit and open (or update) a PR</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ github.token }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s"># Nothing changed: clean exit, no branch, no PR.</span>
          <span class="s">git diff --quiet &amp;&amp; exit 0</span>

          <span class="s">git config user.name "github-actions[bot]"</span>
          <span class="s">git config user.email "github-actions[bot]@users.noreply.github.com"</span>

          <span class="s">BRANCH=autogenerated-files</span>
          <span class="s">git switch -C "${BRANCH}"</span>
          <span class="s">git commit -am "Update autogenerated files"</span>
          <span class="s"># Force-push so the branch always matches the latest run.</span>
          <span class="s">git push --force origin "${BRANCH}"</span>

          <span class="s"># Open the PR only if one isn't already there.</span>
          <span class="s">gh pr view "${BRANCH}" &amp;&gt;/dev/null ||</span>
            <span class="s">gh pr create --head "${BRANCH}" \</span>
              <span class="s">--title "Update autogenerated files" \</span>
              <span class="s">--body "Automated update of autogenerated files."</span>
</code></pre></div></div>

<p>This avoids having developers remember to run these and make a PR for them.
It also helps catch drift between environments.</p>

<p>If your team is happy with it: you can also make these trigger on <code class="language-plaintext highlighter-rouge">push</code> events on PRs and auto-update files within a PR e.g. fixing lints.</p>

<h2 id="-cron-jobs">⏰ Cron Jobs</h2>

<p>I’ve very deliberately not had a personal server for many years.
I really like avoiding the maintenance and security burden of running one.
I prefer PaaS vendors (e.g. DigitalOcean) for hosting apps but often I just have some unrelated task I want to run on a schedule.</p>

<p>GitHub Actions works nicely for this use case.
You can have a <code class="language-plaintext highlighter-rouge">cron</code> line on <code class="language-plaintext highlighter-rouge">schedule</code>, a <code class="language-plaintext highlighter-rouge">workflow_dispatch</code> to trigger it on demand and have it automatically run on various other GitHub events or its own change.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">on</span><span class="pi">:</span>
  <span class="na">schedule</span><span class="pi">:</span>
    <span class="c1"># Every day at 07:00 UTC. Cron is always UTC, so mind your timezone.</span>
    <span class="pi">-</span> <span class="na">cron</span><span class="pi">:</span> <span class="s2">"</span><span class="s">0</span><span class="nv"> </span><span class="s">7</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*</span><span class="nv"> </span><span class="s">*"</span>
  <span class="c1"># Re-run (as a dry-run) whenever the script or workflow itself changes.</span>
  <span class="na">push</span><span class="pi">:</span>
    <span class="na">paths</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">.github/scripts/sync.rb</span>
      <span class="pi">-</span> <span class="s">.github/workflows/sync.yml</span>
  <span class="na">workflow_dispatch</span><span class="pi">:</span>

<span class="na">permissions</span><span class="pi">:</span>
  <span class="na">contents</span><span class="pi">:</span> <span class="s">read</span>

<span class="na">jobs</span><span class="pi">:</span>
  <span class="na">sync</span><span class="pi">:</span>
    <span class="na">runs-on</span><span class="pi">:</span> <span class="s">ubuntu-latest</span>
    <span class="na">concurrency</span><span class="pi">:</span>
      <span class="na">group</span><span class="pi">:</span> <span class="s">sync-${{ github.ref_name }}</span>
      <span class="na">cancel-in-progress</span><span class="pi">:</span> <span class="kc">true</span>
    <span class="na">steps</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/checkout@v7</span>
        <span class="na">with</span><span class="pi">:</span>
          <span class="na">persist-credentials</span><span class="pi">:</span> <span class="kc">false</span>
      <span class="pi">-</span> <span class="na">uses</span><span class="pi">:</span> <span class="s">ruby/setup-ruby@v1</span>

      <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Sync (dry-run on push)</span>
        <span class="na">env</span><span class="pi">:</span>
          <span class="na">API_TOKEN</span><span class="pi">:</span> <span class="s">${{ secrets.API_TOKEN }}</span>
        <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
          <span class="s">if [ "${{ github.event_name }}" = "push" ]; then</span>
            <span class="s">.github/scripts/sync.rb --dry-run</span>
          <span class="s">else</span>
            <span class="s">.github/scripts/sync.rb</span>
          <span class="s">fi</span>
</code></pre></div></div>

<p>This lets you run this script regularly without the overhead of maintaining a server.
GitHub Actions’ secrets handling means it’s also fairly easy to do sensitive operations without needing to do so manually or insecurely.
I used to use this to <a href="https://github.com/MikeMcQuaid/TwitterDelete">automatically delete my tweets</a> (before they messed with the API).</p>

<h2 id="-if-you-remember-one-thing">🤖 If You Remember One Thing</h2>

<p>Use GitHub Actions to enforce and automate as much of your workflow as possible.
“Please remember to…” is error-prone and boring.
Let a <a href="/robot-pedantry-human-empathy/">robot’s pedantry</a> provide guarantees instead, so you can spend your attention on the things that actually need a human.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Merge-queue deploys, robust releases and chores you keep forgetting]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/a/make-github-actions-do-more-for-you.png" />
        <media:content medium="image" url="https://mikemcquaid.com/images/a/make-github-actions-do-more-for-you.png" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Homebrew tightens tap security, begins work on its interface</title>
      <link href="https://www.helpnetsecurity.com/2026/06/18/homebrew-6-0-0-released/" rel="alternate" type="text/html" title="Homebrew tightens tap security, begins work on its interface" />
      
        <link href="https://mikemcquaid.com/interviews/homebrew-6-0-0-released/" rel="related" type="text/html" title="Homebrew tightens tap security, begins work on its interface" />
      
      <published>2026-06-18T00:00:00+00:00</published>
      <updated>2026-06-18T00:00:00+00:00</updated>
      <id>https://www.helpnetsecurity.com/2026/06/18/homebrew-6-0-0-released/</id>
      
      <content type="html" xml:base="https://www.helpnetsecurity.com/2026/06/18/homebrew-6-0-0-released/"><![CDATA[<p>Interviewed by Anamarija Pogorelec on Help Net Security.</p>
          <p>“It’s probably aimed a little more at newcomers than experienced
Homebrew users.”</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[“It’s probably aimed a little more at newcomers than experienced Homebrew users.”]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Today, I’m proud to announce Homebrew 6.0.0.</title>
      <link href="https://brew.sh/2026/06/11/homebrew-6.0.0/" rel="alternate" type="text/html" title="Today, I’m proud to announce Homebrew 6.0.0." />
      
        <link href="https://mikemcquaid.com/thoughts/20260611141732/" rel="related" type="text/html" title="Today, I’m proud to announce Homebrew 6.0.0." />
      
      <published>2026-06-11T13:17:32+00:00</published>
      <updated>2026-06-11T13:17:32+00:00</updated>
      <id>https://brew.sh/2026/06/11/homebrew-6.0.0/</id>
      
      <content type="html" xml:base="https://brew.sh/2026/06/11/homebrew-6.0.0/"><![CDATA[<p>Today, I’m proud to announce Homebrew 6.0.0.</p>

<p>Since 5.1.0: secure tap trusting, faster JSON API, Linux sandboxing, better defaults, <code class="language-plaintext highlighter-rouge">brew bundle</code> improvements, improved performance, initial macOS Golden Gate support.</p>

        
        
          <p><a href="https://brew.sh/2026/06/11/homebrew-6.0.0/">https://brew.sh/2026/06/11/homebrew-6.0.0/</a></p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Today, I'm proud to announce Homebrew 6.0.0. Since 5.1.0: secure tap trusting, faster JSON API, Linux sandboxing, better defaults, `brew bundle` improvements, improved performance, initial macOS Golden Gate support.]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Flood of AI ‘garbage’ is pushing open-source developers to the limit</title>
      <link href="https://www.newscientist.com/article/2527761-flood-of-ai-garbage-is-pushing-open-source-developers-to-the-limit/" rel="alternate" type="text/html" title="Flood of AI ‘garbage’ is pushing open-source developers to the limit" />
      
        <link href="https://mikemcquaid.com/interviews/flood-of-ai-garbage-is-pushing-open-source-developers-to-the-limit/" rel="related" type="text/html" title="Flood of AI ‘garbage’ is pushing open-source developers to the limit" />
      
      <published>2026-06-05T00:00:00+00:00</published>
      <updated>2026-06-05T00:00:00+00:00</updated>
      <id>https://www.newscientist.com/article/2527761-flood-of-ai-garbage-is-pushing-open-source-developers-to-the-limit/</id>
      
      <content type="html" xml:base="https://www.newscientist.com/article/2527761-flood-of-ai-garbage-is-pushing-open-source-developers-to-the-limit/"><![CDATA[<p>Interviewed by Matthew Sparkes on New Scientist.</p>
          <p>“The skill right now is being able to skim and spot nonsense while investing as little of your own time as you possibly can.”</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[“The skill right now is being able to skim and spot nonsense while investing as little of your own time as you possibly can.”]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>The impact of AI on open source software development</title>
      <link href="https://mikemcquaid.com/talks/the-impact-of-ai-on-open-source-software-development/" rel="alternate" type="text/html" title="The impact of AI on open source software development" />
      
        <link href="https://mikemcquaid.com/interviews/flood-of-ai-garbage-is-pushing-open-source-developers-to-the-limit/" rel="related" type="text/html" title="The impact of AI on open source software development" />
      
      <published>2026-06-05T00:00:00+00:00</published>
      <updated>2026-06-05T00:00:00+00:00</updated>
      <id>https://mikemcquaid.com/talks/the-impact-of-ai-on-open-source-software-development/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/talks/the-impact-of-ai-on-open-source-software-development/"><![CDATA[<p>Panel at <a href="https://stateofopencon.com/edinburgh-soocon26/">SOOCon26 Edinburgh</a>.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Five experienced open source practitioners cut through the hype to ask what AI is actually doing to the communities, projects, and humans that keep open source alive.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/default-card.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/default-card.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>“It’s the duty of all Free Software developers to steal as much time…</title>
      <link href="https://mikemcquaid.com/thoughts/20260514131932/" rel="alternate" type="text/html" title="“It’s the duty of all Free Software developers to steal as much time…" />
      
        <link href="https://mikemcquaid.com/interviews/flood-of-ai-garbage-is-pushing-open-source-developers-to-the-limit/" rel="related" type="text/html" title="“It’s the duty of all Free Software developers to steal as much time…" />
      
      <published>2026-05-14T12:19:32+00:00</published>
      <updated>2026-05-14T12:19:32+00:00</updated>
      <id>https://mikemcquaid.com/thoughts/20260514131932/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/thoughts/20260514131932/"><![CDATA[<p>“It’s the duty of all Free Software developers to steal as much time as they can from their employers for software freedom.”</p>

<p>Jeremy Allison, co-creator of Samba and, at the time, a Google employee.</p>

<p>🫡</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA["It's the duty of all Free Software developers to steal as much time as they can from their employers for software freedom." Jeremy Allison, co-creator of Samba and, at the time, a Google employee. 🫡]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/me.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/me.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Open source maintainers at profitable companies: stop asking…</title>
      <link href="https://ossresistance.com" rel="alternate" type="text/html" title="Open source maintainers at profitable companies: stop asking…" />
      
        <link href="https://mikemcquaid.com/thoughts/20260513154346/" rel="related" type="text/html" title="Open source maintainers at profitable companies: stop asking…" />
      
      <published>2026-05-13T14:43:46+00:00</published>
      <updated>2026-05-13T14:43:46+00:00</updated>
      <id>https://ossresistance.com</id>
      
      <content type="html" xml:base="https://ossresistance.com"><![CDATA[<p>Open source maintainers at profitable companies: stop asking permission to fix what your employer already depends on.</p>

<p>No paperwork. No programme. No manager’s blessing. Just maintain it on the clock.</p>

        
        
          <p><a href="https://ossresistance.com">https://ossresistance.com</a></p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Open source maintainers at profitable companies: stop asking permission to fix what your employer already depends on. No paperwork. No programme. No manager's blessing. Just maintain it on the clock.]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Your regular reminder that shitting on OSS on social media is a…</title>
      <link href="https://mikemcquaid.com/thoughts/20260508123635/" rel="alternate" type="text/html" title="Your regular reminder that shitting on OSS on social media is a…" />
      
        <link href="https://mikemcquaid.com/thoughts/20260513154346/" rel="related" type="text/html" title="Your regular reminder that shitting on OSS on social media is a…" />
      
      <published>2026-05-08T11:36:35+00:00</published>
      <updated>2026-05-08T11:36:35+00:00</updated>
      <id>https://mikemcquaid.com/thoughts/20260508123635/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/thoughts/20260508123635/"><![CDATA[<p>Your regular reminder that shitting on OSS on social media is a selfish thing to do.</p>

<p>Good job sapping volunteer maintainers’ motivation in exchange for your “internet points”.</p>

<p>Next time: try rolling up your sleeves and contribute a fix to the problem you’ve identified.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Your regular reminder that shitting on OSS on social media is a selfish thing to do. Good job sapping volunteer maintainers' motivation in exchange for your "internet points". Next time: try rolling up your sleeves and contribute a fix to the problem you've identified.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/me.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/me.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>I wonder how much of people loving or hating meetings is down to how…</title>
      <link href="https://mikemcquaid.com/thoughts/20260504145430/" rel="alternate" type="text/html" title="I wonder how much of people loving or hating meetings is down to how…" />
      
        <link href="https://mikemcquaid.com/thoughts/20260513154346/" rel="related" type="text/html" title="I wonder how much of people loving or hating meetings is down to how…" />
      
      <published>2026-05-04T13:54:30+00:00</published>
      <updated>2026-05-04T13:54:30+00:00</updated>
      <id>https://mikemcquaid.com/thoughts/20260504145430/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/thoughts/20260504145430/"><![CDATA[<p>I wonder how much of people loving or hating meetings is down to how well they can type or multitask.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[I wonder how much of people loving or hating meetings is down to how well they can type or multitask.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/me.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/me.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>“I’m excited to work with you, the company seems great.</title>
      <link href="https://mikemcquaid.com/thoughts/20260421122042/" rel="alternate" type="text/html" title="“I’m excited to work with you, the company seems great." />
      
        <link href="https://mikemcquaid.com/thoughts/20260513154346/" rel="related" type="text/html" title="“I’m excited to work with you, the company seems great." />
      
      <published>2026-04-21T11:20:42+00:00</published>
      <updated>2026-04-21T11:20:42+00:00</updated>
      <id>https://mikemcquaid.com/thoughts/20260421122042/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/thoughts/20260421122042/"><![CDATA[<p>“I’m excited to work with you, the company seems great. I’m a little unwhelmed with the salary, though, is there any chance you can do better?”</p>

<p>This sentence gets most who try a 0-10% new job pay increase with zero resentments.</p>

<p>Paraphrase it and use it (even on me).</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA["I'm excited to work with you, the company seems great. I'm a little unwhelmed with the salary, though, is there any chance you can do better?" This sentence gets most who try a 0-10% new job pay increase with zero resentments. Paraphrase it and use it (even on me).]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/me.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/me.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>This AI Tool Rips Off Open Source Software Without Violating Copyright</title>
      <link href="https://www.404media.co/this-ai-tool-rips-off-open-source-software-without-violating-copyright/" rel="alternate" type="text/html" title="This AI Tool Rips Off Open Source Software Without Violating Copyright" />
      
        <link href="https://mikemcquaid.com/interviews/this-ai-tool-rips-off-open-source-software-without-violating-copyright/" rel="related" type="text/html" title="This AI Tool Rips Off Open Source Software Without Violating Copyright" />
      
      <published>2026-04-21T00:00:00+00:00</published>
      <updated>2026-04-21T00:00:00+00:00</updated>
      <id>https://www.404media.co/this-ai-tool-rips-off-open-source-software-without-violating-copyright/</id>
      
      <content type="html" xml:base="https://www.404media.co/this-ai-tool-rips-off-open-source-software-without-violating-copyright/"><![CDATA[<p>Interviewed by Emanuel Maiberg on 404 Media.</p>
          <p>“The ethics fucking suck. Open source isn’t just source code you
download once. It’s an ongoing relationship.”</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[“The ethics fucking suck. Open source isn’t just source code you download once. It’s an ongoing relationship.”]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>This was a good read and reflects my experiences.</title>
      <link href="https://christophermeiklejohn.com/ai/engineering/2026/04/01/software-engineering-is-becoming-civil-engineering.html" rel="alternate" type="text/html" title="This was a good read and reflects my experiences." />
      
        <link href="https://mikemcquaid.com/thoughts/20260414133924/" rel="related" type="text/html" title="This was a good read and reflects my experiences." />
      
      <published>2026-04-14T12:39:24+00:00</published>
      <updated>2026-04-14T12:39:24+00:00</updated>
      <id>https://christophermeiklejohn.com/ai/engineering/2026/04/01/software-engineering-is-becoming-civil-engineering.html</id>
      
      <content type="html" xml:base="https://christophermeiklejohn.com/ai/engineering/2026/04/01/software-engineering-is-becoming-civil-engineering.html"><![CDATA[<p>This was a good read and reflects my experiences. It also made me think the answer to “what do we do with juniors/students and AI” is “actually teach them software engineering best practices, not just CS fundamentals”.</p>

        
        
          <p><a href="https://christophermeiklejohn.com/ai/engineering/2026/04/01/software-engineering-is-becoming-civil-engineering.html">https://christophermeiklejohn.com/ai/engineering/2026/04/01/software-engineering-is-becoming-civil-engineering.html</a></p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[This was a good read and reflects my experiences. It also made me think the answer to "what do we do with juniors/students and AI" is "actually teach them software engineering best practices, not just CS fundamentals".]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Sandboxes and Worktrees: My secure Agentic AI Setup</title>
      <link href="https://mikemcquaid.com/sandboxed-agent-worktrees-my-coding-and-ai-setup-in-2026/" rel="alternate" type="text/html" title="Sandboxes and Worktrees: My secure Agentic AI Setup" />
      
        <link href="https://mikemcquaid.com/thoughts/20260414133924/" rel="related" type="text/html" title="Sandboxes and Worktrees: My secure Agentic AI Setup" />
      
      <published>2026-04-14T00:00:00+00:00</published>
      <updated>2026-04-14T00:00:00+00:00</updated>
      <id>https://mikemcquaid.com/sandboxed-agent-worktrees-my-coding-and-ai-setup-in-2026/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/sandboxed-agent-worktrees-my-coding-and-ai-setup-in-2026/"><![CDATA[<p>I’ve been using AI tools since early 2021 when I was invited to test out the Copilot internal alpha at GitHub (where I spent 10 years).
I’ve maintained <a href="https://brew.sh">Homebrew</a> since 2009.
I’ve now personally hit the “AI writes 90% of my code” (<a href="https://www.cfr.org/event/ceo-speaker-series-dario-amodei-anthropic">Dario Amodei’s early 2025 prediction</a> for late 2025).
I’ve been asked by a few folks to detail my current setup so: here it is.</p>

<p>TL;DR:</p>

<ol>
  <li><strong>Agents</strong> bring a step change from code completion to code generation and are good enough now to one-shot many problems</li>
  <li><strong>Sandboxing</strong> improves security and productivity by letting agents run wild without babysitting permission prompts</li>
  <li><strong>Git worktrees</strong> parallelise work so more tokens/spend directly translates to more velocity</li>
</ol>

<h2 id="-agents">🤖 Agents</h2>

<p><img src="https://mikemcquaid.com/images/a/codex.png" alt="OpenAI Codex" /></p>

<p>If you’re still using AI in “code completion mode” or only GitHub Copilot, you’re missing out.
Mid-to-late 2025 was when agentic tools like Claude Code and OpenAI Codex got good enough that prompting became quicker than editing, even when you’re anal about it.</p>

<p>My experience of Claude Code and OpenAI Codex has mostly been:</p>

<ul>
  <li>OpenAI Codex (5.4 <code class="language-plaintext highlighter-rouge">xhigh</code>): takes a while, generally does things mostly right first time, doesn’t need much prompting/steering</li>
  <li>Claude Code (Opus 4.6 <code class="language-plaintext highlighter-rouge">max</code>): fairly stupid by default, can be nudged with aggressive hooks/tools/prompts to being less so
    <ul>
      <li>(Opus 4.7 just got released: let’s see if it’s less stupid…)</li>
    </ul>
  </li>
</ul>

<p>My daily driver of choice is OpenAI Codex but I run out of tokens more quickly so have learned to be fine with either.
(OpenAI: please give me the free tokens I’ve applied for as an OSS maintainer, thanks &lt;3).</p>

<p>A lot of people spend a lot of time and energy thinking about their <code class="language-plaintext highlighter-rouge">CLAUDE.md</code>/<code class="language-plaintext highlighter-rouge">AGENTS.md</code>.
My experience is their performance varies so much from model to model, version to version that it’s worth keeping them as minimal as possible.
I have an <a href="https://github.com/MikeMcQuaid/dotfiles/blob/main/AGENTS-GLOBAL.md"><code class="language-plaintext highlighter-rouge">AGENTS-GLOBAL.md</code> in my dotfiles</a> that provides a decent minimum of what I care about across all projects in Claude and Codex.</p>

<p>The main problem you’ll bump into pretty quickly with agents is: you have to spend half your life going “Yes, do this safe thing”, “No, don’t do this dangerous thing”.
This is boring and slow.
I’m lazy so needed better automation.</p>

<h2 id="️-sandvault">🏝️ Sandvault</h2>

<p><img src="https://mikemcquaid.com/images/a/sv-claude.png" alt="Claude Code under Sandvault" /></p>

<p>The various agents have various “bypass permission checks”, “run without sandbox”, “YOLO”, etc. modes.</p>

<p>If you want to be actually productive with these tools you basically have two options:</p>

<ol>
  <li>decide you’re just going to play with fire and disable permissions and hope nothing goes wrong</li>
  <li>run in a sandboxed environment e.g. a VM, separate machine, sandbox with reduced (system) permissions, access, tokens, etc.</li>
</ol>

<p>I picked option 2 because I take my responsibility as a Homebrew maintainer seriously to not do stupid insecure shit on my machine.
Unfortunately, also because I’m a Homebrew maintainer, I’m allergic to using Docker for local macOS development.</p>

<p><a href="https://github.com/webcoyote/sandvault"><code class="language-plaintext highlighter-rouge">sandvault</code></a> is the nicest middle ground I’ve come across.
It makes use of macOS sandboxes and creates and maintains a separate non-admin user account where you can let it run wild.
Short of exfiltrating your code (which I’m not worried about with OSS), it closes the majority of risk vectors I care about where agents might:</p>

<ul>
  <li>go e.g. <code class="language-plaintext highlighter-rouge">rm -rf</code> on files not in version control</li>
  <li>use my e.g. <code class="language-plaintext highlighter-rouge">GITHUB_TOKEN</code> to do things on sensitive repositories</li>
  <li>exfiltrate sensitive files elsewhere</li>
</ul>

<p>Once installed (<code class="language-plaintext highlighter-rouge">brew install sandvault</code>), you can run <code class="language-plaintext highlighter-rouge">sv codex</code> or <code class="language-plaintext highlighter-rouge">sv claude</code> to start your agent of choice or <code class="language-plaintext highlighter-rouge">sv shell</code> to start a shell.</p>

<p>You can also put your dotfiles under <code class="language-plaintext highlighter-rouge">/Users/Shared/sv-${USER}/user</code> and they will be copied to the relevant sandvault e.g. (<code class="language-plaintext highlighter-rouge">sandvault-mike</code>) user.</p>

<p>Take a look at <a href="https://github.com/MikeMcQuaid/dotfiles/blob/2aa9c154cdd597138c0924330f28a77da6689234/script/setup#L169-L204">my dotfiles’ <code class="language-plaintext highlighter-rouge">script/sync</code> if you want an example of how to do this</a>.</p>

<p>I also recommend using a different-coloured prompt for your Sandvault user so you know when you’re inside it.
See my dotfiles <a href="https://github.com/MikeMcQuaid/dotfiles/blob/2aa9c154cdd597138c0924330f28a77da6689234/shprofile.sh#L20"><code class="language-plaintext highlighter-rouge">shprofile.sh</code></a> and <a href="https://github.com/MikeMcQuaid/dotfiles/blob/2aa9c154cdd597138c0924330f28a77da6689234/zprofile.sh#L42-L43"><code class="language-plaintext highlighter-rouge">zprofile.sh</code></a> for examples.</p>

<h2 id="-sharing">🤝 Sharing</h2>

<p>This all works nicely but: what if you want to share code more easily between your current <code class="language-plaintext highlighter-rouge">$USER</code> (e.g. <code class="language-plaintext highlighter-rouge">mike</code>) and the unprivileged sandvault (e.g. <code class="language-plaintext highlighter-rouge">sandvault-mike</code>) user?</p>

<p>I would normally clone all my OSS repositories into <code class="language-plaintext highlighter-rouge">~/OSS/*</code> and employer’s (currently <a href="https://getadministrate.com">Administrate</a>) into e.g. <code class="language-plaintext highlighter-rouge">~/Administrate</code>.
Instead, I now clone under the Sandvault-created <code class="language-plaintext highlighter-rouge">/Users/Shared/sv-mike</code> into <code class="language-plaintext highlighter-rouge">/Users/Shared/sv-mike/repositories</code> and create <code class="language-plaintext highlighter-rouge">/Users/Shared/sv-mike/worktrees</code> (more on that later).</p>

<p>This lets me have somewhere safe that’s readable and writable to both users.
Note, you’ll need to add to your <code class="language-plaintext highlighter-rouge">~/.gitconfig</code> for both to not freak out <code class="language-plaintext highlighter-rouge">git</code> with the group writable permissions:</p>

<div class="language-config highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[<span class="n">safe</span>]
	<span class="c"># It's expected that sandvault directories are owned by another user.
</span>	<span class="n">directory</span> = /<span class="n">Users</span>/<span class="n">Shared</span>/<span class="n">sv</span>-<span class="n">mike</span>/<span class="n">repositories</span>/*
</code></pre></div></div>

<h2 id="-worktrees">🌳 Worktrees</h2>

<p><img src="https://mikemcquaid.com/images/a/superset.png" alt="Superset" /></p>

<p>Once I had Sandvault working nicely with Claude and Codex I could be a lot more productive with just letting them work independently.
However, running one agent at a time becomes the bottleneck when you’re paying for more tokens than you’re currently using.
Multitasking between multiple repositories was an easy next step but I found myself wanting to do this more on the same repository.
I ended up with a <code class="language-plaintext highlighter-rouge">homebrew</code> and <code class="language-plaintext highlighter-rouge">homebrew2</code> repository which felt gross but kinda worked.
The problem was remembering what I did on which one.</p>

<p>Git worktrees let you have multiple branches of the same repository checked out simultaneously in separate directories.
I knew they were probably the right solution here (I <a href="https://mikemcquaid.com/gitinpractice">wrote a book about Git</a> so have no excuse) but it’d been ages since I’d played with them.
I also didn’t want to have to build all this manually.
I’d already built a bunch of <code class="language-plaintext highlighter-rouge">git</code> helper aliases around Sandvault.</p>

<p>A <a href="https://gusfune.com">talented CTO friend</a> pointed me at <a href="https://docs.conductor.build">Conductor</a> as a way of running a bunch of agents with worktrees.
It had potential but I love Sandvault too much and couldn’t figure out any way to make them play nicely.</p>

<p>Instead, I stumbled upon <a href="https://superset.sh">Superset</a> which did similar but, importantly, allowed me to override commands.</p>

<p>I configured my “Worktree location” to <code class="language-plaintext highlighter-rouge">/Users/Shared/sv-mike/worktrees</code>.
I set my “Agents” to use their Sandvault commands (same for “No Prompt” and “With Prompt” options):</p>
<ul>
  <li>Claude: <code class="language-plaintext highlighter-rouge">sv claude --</code></li>
  <li>Codex: <code class="language-plaintext highlighter-rouge">sv codex --</code></li>
  <li>Gemini: <code class="language-plaintext highlighter-rouge">sv gemini --</code></li>
  <li>OpenCode: <code class="language-plaintext highlighter-rouge">sv opencode --</code></li>
</ul>

<p>These are all those that Sandvault supports today (I easily added OpenCode a few days ago with a few lines of code).</p>

<p>I then added a bunch of “Projects” based on those I’d cloned into <code class="language-plaintext highlighter-rouge">/Users/Shared/sv-mike/worktrees</code>.
For those where it’s useful, I have them run a basic e.g. <code class="language-plaintext highlighter-rouge">script/bootstrap</code> so the project is better set up.</p>

<h2 id="-prompting">🙋 Prompting</h2>

<p>Once this is all set up, you can easily spin up terminals for each project and run whatever tool or agent you choose there.
Creating worktrees is where this actually gets fun and powerful though:</p>

<p><img src="https://mikemcquaid.com/images/a/superset-prompt.png" alt="Superset worktree prompt" /></p>

<p>This lets you spin up an agent in a sandboxed new worktree based on a single prompt.</p>

<p>Once you have this working: the sky is the limit.
My personal workflow has gone from:</p>
<ul>
  <li>“reading Homebrew or work code problem, add to my TODO list”</li>
</ul>

<p>to:</p>
<ul>
  <li>“copy paste problem description plus braindump of how I think it should be solved into a prompt, let the agent work on it”</li>
</ul>

<p>Sometimes I’ll just fire up multiple agents with different approaches to run at the same time and throw away those I like the least.</p>

<h2 id="-review">🔍 Review</h2>

<p><img src="https://mikemcquaid.com/images/a/fork.png" alt="Fork Git GUI" /></p>

<p>I always review any agent-produced work locally before I share it with others.
Review can involve one or more of:</p>
<ul>
  <li>reading all generated output (e.g. using <a href="https://git-fork.com">Fork</a>, a nice macOS Git GUI)</li>
  <li>manually editing generated output (e.g. using <a href="https://zed.dev">Zed</a>, my current editor of choice)
    <ul>
      <li>I picked Zed because I spend less time in my editor now, don’t need Cursor’s better autocomplete and care more about startup speed</li>
    </ul>
  </li>
  <li>prompting to force edits of generated output (e.g. providing local code review comments as new prompts)</li>
  <li>manually performing verification tests (e.g. running things locally, reviewing the output, giving the AI error messages)</li>
  <li>getting another AI to review the work of the AI (e.g. Copilot Code review in PRs)</li>
  <li>providing CI failures (e.g. GitHub Actions output)</li>
</ul>

<p>How many of these I do depends on my familiarity with the code, its criticality and how confident I am in other guardrails e.g. CI, human review.</p>

<p>I make this easier with Zed (<code class="language-plaintext highlighter-rouge">zed .; exit</code>) and Fork (<code class="language-plaintext highlighter-rouge">fork .; exit</code>) “Presets” in Superset to launch them in the worktree with one click.</p>

<p>When reviewing AI-generated work from others, I review the output and sometimes manually test.
I’m lazier there, though.
If AI is writing your code for you now, you need to step up and do more in the way of testing for your reviewers/coworkers.</p>

<p>We’ve set higher barriers here in Homebrew now including:</p>
<ul>
  <li>requiring AI disclosure on PRs</li>
  <li>requiring non-maintainers do not have more than 1 AI generated PR open at once</li>
  <li>closing without comment when AIs create the PR and discard our PR template</li>
  <li>requiring PRs that are too large be split into multiple, smaller ones</li>
  <li>blocking people who refuse to stop creating low-quality AI PRs</li>
</ul>

<p>This is still sometimes tiring and demotivating though compared to reviewing the work purely of humans.
As a result, we will sometimes just close out PRs where it feels like we’re speaking to their agent and not the human.</p>

<h2 id="‍-ctpo-assistant">🧑‍💼 CT(P)O Assistant</h2>

<p>If you’ve read all this and gone “aren’t you a CTPO? shouldn’t you be mostly doing non-coding things?”:</p>

<ul>
  <li>I am, it’s just not very interesting to read about if you’re an engineer</li>
  <li>Ok, if you insist: I have another cool thing to show you</li>
</ul>

<p>I read this <a href="https://x.com/obie/status/2013955736292704342">tweet from Obie Fernandez</a> about a CTO executive assistant and was intrigued.
I’m on my second CTPO job and feel fairly organised but that <a href="/how-i-get-things-done/">my usual systems</a> plus my memory fail the huge amount of context I now need to do my job well.
I’ve never had a human executive assistant and strongly suspect I’d be too much of a control freak to handle one.</p>

<p>In Superset, I have a project called <code class="language-plaintext highlighter-rouge">ctpo</code>.
In this I put in various meeting notes, my goals, company goals, personal TODOs, etc.</p>

<p>I can then ask it questions to help me prepare for meetings, what my short/medium/long-term priorities are and do research.
The initial “training” was done on internal engineering culture documents I’ve written and the written corpus on this website.
This corpus was helped by, again thanks to modern AI tooling, storing <a href="https://github.com/MikeMcQuaid/mikemcquaid.com/tree/main/_data/transcripts">transcripts</a> from various talks and podcasts I’ve done along with my posts.</p>

<p>This has given me a personal assistant that already knows most of my high-level values and gives me a vastly better memory (which is mostly accurate).</p>

<h2 id="-conclusion">🎬 Conclusion</h2>

<p>GitHub reached out recently and apparently Homebrew is one of a smaller number of projects that’s seen an uptick rather than downtick in merges post-AI agents.
I don’t think that’s a coincidence: this setup is a big part of why.</p>

<p>Between Claude/Codex, Sandvault, Superset and my CTPO assistant I feel the most productive and organised I’ve ever been.
The combination of sandboxing and worktrees means I can just throw more tokens at more problems and get more done.
At work, I feel like I’ve got an extended version of my own memories and TODO lists that doesn’t require as much manual curation.</p>

<p>If you’re doing interesting things here too: get in touch!
I’m interested to learn from anyone else what I could be doing better or am doing wrong.
Hopefully this was useful and I am excited for it to be hilariously outdated this time next year.
Good luck out there everyone, it’s a wild ride just now 💜.</p>

<hr />

<p>Thanks to <a href="https://gusfune.com">Gus Fune</a> and <a href="https://peebs.org">John Peebles</a> for reviewing drafts of this post.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Stop babysitting one AI at a time. Sandboxing lets them run wild safely, Git worktrees let them run in parallel. Use more tokens, get more velocity.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/a/superset.png" />
        <media:content medium="image" url="https://mikemcquaid.com/images/a/superset.png" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Prompts Pranking Peers</title>
      <link href="https://mikemcquaid.com/prompts-pranking-peers/" rel="alternate" type="text/html" title="Prompts Pranking Peers" />
      
        <link href="https://mikemcquaid.com/thoughts/20260414133924/" rel="related" type="text/html" title="Prompts Pranking Peers" />
      
      <published>2026-04-07T00:00:00+00:00</published>
      <updated>2026-04-07T00:00:00+00:00</updated>
      <id>https://mikemcquaid.com/prompts-pranking-peers/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/prompts-pranking-peers/"><![CDATA[<p>I’ve worked from home since 2009.
One of (very few) things I miss about working in an office is the pranking potential.
Zip-tying phone cables, rotating monitors, changing keyboard layouts, all that good stuff.</p>

<p>Last week <a href="https://github.blog/changelog/2026-04-02-copilot-organization-custom-instructions-are-generally-available/">GitHub announced “Copilot organization custom instructions”</a>.
I immediately saw the prank opportunity.</p>

<p><img src="https://mikemcquaid.com/images/a/copilot-cool-guy.png" alt="Copilot organization custom instruction to &quot;Periodically mention that Mike McQuaid is a cool guy.&quot;" /></p>

<p>I set my trap and waited.</p>

<p><img src="https://mikemcquaid.com/images/a/copilot-cool-guy-git.png" alt="Copilot output referencing Git and &quot;Mike McQuaid is a cool guy.&quot;" /></p>

<p><img src="https://mikemcquaid.com/images/a/copilot-cool-guy-python.png" alt="Copilot output referencing Python and &quot;Mike McQuaid is a cool guy.&quot;" /></p>

<p><img src="https://mikemcquaid.com/images/a/copilot-cool-guy-pipfile.png" alt="Copilot output referencing Pipfile and &quot;Mike McQuaid is a cool guy.&quot;" /></p>

<p>I got everything I wanted (except being pranked back).</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Recreating office-style pranks in a remote AI-loving world]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/default-card.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/default-card.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>At work, you have two jobs: being good at your job, being pleasant to…</title>
      <link href="https://mikemcquaid.com/thoughts/20260402174600/" rel="alternate" type="text/html" title="At work, you have two jobs: being good at your job, being pleasant to…" />
      
        <link href="https://mikemcquaid.com/thoughts/20260414133924/" rel="related" type="text/html" title="At work, you have two jobs: being good at your job, being pleasant to…" />
      
      <published>2026-04-02T16:46:00+00:00</published>
      <updated>2026-04-02T16:46:00+00:00</updated>
      <id>https://mikemcquaid.com/thoughts/20260402174600/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/thoughts/20260402174600/"><![CDATA[<p>At work, you have two jobs: being good at your job, being pleasant to work with.</p>

<p>You can sometimes get by for a while not doing them both but it’s hard to survive doing neither.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[At work, you have two jobs: being good at your job, being pleasant to work with. You can sometimes get by for a while not doing them both but it's hard to survive doing neither.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/me.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/me.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Every time you open an issue or pull request with “No description…</title>
      <link href="https://mikemcquaid.com/thoughts/20260401123545/" rel="alternate" type="text/html" title="Every time you open an issue or pull request with “No description…" />
      
        <link href="https://mikemcquaid.com/thoughts/20260414133924/" rel="related" type="text/html" title="Every time you open an issue or pull request with “No description…" />
      
      <published>2026-04-01T11:35:45+00:00</published>
      <updated>2026-04-01T11:35:45+00:00</updated>
      <id>https://mikemcquaid.com/thoughts/20260401123545/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/thoughts/20260401123545/"><![CDATA[<p>Every time you open an issue or pull request with “No description provided”, an open source maintainer dies.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Every time you open an issue or pull request with "No description provided", an open source maintainer dies.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/me.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/me.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Ruby Central report reopens wounds over RubyGems repo takeover</title>
      <link href="https://www.theregister.com/2026/04/01/ruby_central_report/" rel="alternate" type="text/html" title="Ruby Central report reopens wounds over RubyGems repo takeover" />
      
        <link href="https://mikemcquaid.com/interviews/ruby-central-report-reopens-wounds-over-rubygems-repo-takeover/" rel="related" type="text/html" title="Ruby Central report reopens wounds over RubyGems repo takeover" />
      
      <published>2026-04-01T00:00:00+00:00</published>
      <updated>2026-04-01T00:00:00+00:00</updated>
      <id>https://www.theregister.com/2026/04/01/ruby_central_report/</id>
      
      <content type="html" xml:base="https://www.theregister.com/2026/04/01/ruby_central_report/"><![CDATA[<p>Interviewed by The Register.</p>
          <p>“If your project hasn’t argued about governance or money yet, it will one day. Be prepared and try to do this before it becomes a problem.”</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[“If your project hasn’t argued about governance or money yet, it will one day. Be prepared and try to do this before it becomes a problem.”]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>One of the strengths of Homebrew, despite it being unpopular, is…</title>
      <link href="https://nesbitt.io/2026/03/31/npms-defaults-are-bad.html" rel="alternate" type="text/html" title="One of the strengths of Homebrew, despite it being unpopular, is…" />
      
        <link href="https://mikemcquaid.com/thoughts/20260331192849/" rel="related" type="text/html" title="One of the strengths of Homebrew, despite it being unpopular, is…" />
      
      <published>2026-03-31T18:28:49+00:00</published>
      <updated>2026-03-31T18:28:49+00:00</updated>
      <id>https://nesbitt.io/2026/03/31/npms-defaults-are-bad.html</id>
      
      <content type="html" xml:base="https://nesbitt.io/2026/03/31/npms-defaults-are-bad.html"><![CDATA[<p>One of the strengths of Homebrew, despite it being unpopular, is being willing to break backwards compatibility when necessary.</p>

<p>NPM’s unwillingness to do so reflects GitHub’s: both show excessive caution that harm both security and usability.</p>

        
        
          <p><a href="https://nesbitt.io/2026/03/31/npms-defaults-are-bad.html">https://nesbitt.io/2026/03/31/npms-defaults-are-bad.html</a></p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[One of the strengths of Homebrew, despite it being unpopular, is being willing to break backwards compatibility when necessary. NPM's unwillingness to do so reflects GitHub's: both show excessive caution that harm both security and usability.]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>What happened to RubyGems and what can we learn?</title>
      <link href="https://mikemcquaid.com/talks/what-happened-to-rubygems-and-what-can-we-learn/" rel="alternate" type="text/html" title="What happened to RubyGems and what can we learn?" />
      
        <link href="https://mikemcquaid.com/thoughts/20260331192849/" rel="related" type="text/html" title="What happened to RubyGems and what can we learn?" />
      
      <published>2026-01-31T00:00:00+00:00</published>
      <updated>2026-01-31T00:00:00+00:00</updated>
      <id>https://mikemcquaid.com/talks/what-happened-to-rubygems-and-what-can-we-learn/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/talks/what-happened-to-rubygems-and-what-can-we-learn/"><![CDATA[<p>Presented at <a href="https://fosdem.org/2026/schedule/event/YUJUKD-what_happened_to_rubygems_and_what_can_we_learn/">FOSDEM 2026</a>.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Lessons for non-Ruby projects on non-profits, governance, money and access in open source, drawn from the RubyGems dispute.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/default-card.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/default-card.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Package Management Learnings from Homebrew</title>
      <link href="https://mikemcquaid.com/talks/package-management-learnings-from-homebrew/" rel="alternate" type="text/html" title="Package Management Learnings from Homebrew" />
      
        <link href="https://mikemcquaid.com/thoughts/20260331192849/" rel="related" type="text/html" title="Package Management Learnings from Homebrew" />
      
      <published>2026-01-31T00:00:00+00:00</published>
      <updated>2026-01-31T00:00:00+00:00</updated>
      <id>https://mikemcquaid.com/talks/package-management-learnings-from-homebrew/</id>
      
      <content type="html" xml:base="https://mikemcquaid.com/talks/package-management-learnings-from-homebrew/"><![CDATA[<p>Presented at <a href="https://fosdem.org/2026/schedule/event/FGBYKV-package_management_learnings_from_homebrew/">FOSDEM 2026</a>.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Homebrew 5.0.0 released in 2025. Walk through the major changes in 5.0.0, improving expectations based on other package managers and what they can learn from Homebrew's approach.]]></summary>
      

      
      

      
      
        
        <media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mikemcquaid.com/images/default-card.jpg" />
        <media:content medium="image" url="https://mikemcquaid.com/images/default-card.jpg" xmlns:media="http://search.yahoo.com/mrss/" />
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>How Homebrew Became Mac’s Package Manager with Mike McQuaid</title>
      <link href="https://www.lastweekinaws.com/podcast/screaming-in-the-cloud/how-homebrew-became-mac-s-package-manager-with-mike-mcquaid/" rel="alternate" type="text/html" title="How Homebrew Became Mac’s Package Manager with Mike McQuaid" />
      
        <link href="https://mikemcquaid.com/interviews/how-homebrew-became-mac-package-manager-with-mike-mcquaid/" rel="related" type="text/html" title="How Homebrew Became Mac’s Package Manager with Mike McQuaid" />
      
      <published>2026-01-27T00:00:00+00:00</published>
      <updated>2026-01-27T00:00:00+00:00</updated>
      <id>https://www.lastweekinaws.com/podcast/screaming-in-the-cloud/how-homebrew-became-mac-s-package-manager-with-mike-mcquaid/</id>
      
      <content type="html" xml:base="https://www.lastweekinaws.com/podcast/screaming-in-the-cloud/how-homebrew-became-mac-s-package-manager-with-mike-mcquaid/"><![CDATA[<p>Interviewed by Screaming in the Cloud.</p>
          <p>Mike McQuaid explains how Homebrew grew from a side project into macOS’s de facto package manager and how the project is sustained today.</p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[Mike McQuaid explains how Homebrew grew from a side project into macOS’s de facto package manager and how the project is sustained today.]]></summary>
      

      
      

      
      
    </entry>
  
    <entry>
      
      
      
      
      
      
      
      
      
      

      <title>Getting Shit Done in Institutions</title>
      <link href="https://api.riverside.fm/hosting-analytics/media/c0744bf875ca2fe6763dbe3f1a608bea63c7f091e4429bfa638ba97bd3d5a4fc/eyJlcGlzb2RlSWQiOiIwMGZmNDJmZC0yMGE1LTQ3MDUtYmZhMi01MzYzODA2NmQzZmEiLCJwb2RjYXN0SWQiOiI4NWZlZTgzNC1iMWNhLTRlYTItOGEwNy1lMjUyMDdmODQyZGYiLCJhY2NvdW50SWQiOiI2OGQ2YjhlNjU2NDE2OTA2NGI2MzAxMjYiLCJwYXRoIjoibWVkaWEvY2xpcHMvNjk3M2RiMGU5NDc2NDAwMjBjOWMyMmY3L21pa2UtbWNxdWFpZHMtc3R1ZGlvLWNvbXBvc2VyLTIwMjYtMS0yM19fMjEtMzMtMTgubXAzIn0=.mp3" rel="alternate" type="text/html" title="Getting Shit Done in Institutions" />
      
        <link href="https://mikemcquaid.com/interviews/how-homebrew-became-mac-package-manager-with-mike-mcquaid/" rel="related" type="text/html" title="Getting Shit Done in Institutions" />
      
      <published>2026-01-24T12:55:51+00:00</published>
      <updated>2026-01-24T12:55:51+00:00</updated>
      <id>https://api.riverside.fm/hosting-analytics/media/c0744bf875ca2fe6763dbe3f1a608bea63c7f091e4429bfa638ba97bd3d5a4fc/eyJlcGlzb2RlSWQiOiIwMGZmNDJmZC0yMGE1LTQ3MDUtYmZhMi01MzYzODA2NmQzZmEiLCJwb2RjYXN0SWQiOiI4NWZlZTgzNC1iMWNhLTRlYTItOGEwNy1lMjUyMDdmODQyZGYiLCJhY2NvdW50SWQiOiI2OGQ2YjhlNjU2NDE2OTA2NGI2MzAxMjYiLCJwYXRoIjoibWVkaWEvY2xpcHMvNjk3M2RiMGU5NDc2NDAwMjBjOWMyMmY3L21pa2UtbWNxdWFpZHMtc3R1ZGlvLWNvbXBvc2VyLTIwMjYtMS0yM19fMjEtMzMtMTgubXAzIn0=.mp3</id>
      
      <content type="html" xml:base="https://api.riverside.fm/hosting-analytics/media/c0744bf875ca2fe6763dbe3f1a608bea63c7f091e4429bfa638ba97bd3d5a4fc/eyJlcGlzb2RlSWQiOiIwMGZmNDJmZC0yMGE1LTQ3MDUtYmZhMi01MzYzODA2NmQzZmEiLCJwb2RjYXN0SWQiOiI4NWZlZTgzNC1iMWNhLTRlYTItOGEwNy1lMjUyMDdmODQyZGYiLCJhY2NvdW50SWQiOiI2OGQ2YjhlNjU2NDE2OTA2NGI2MzAxMjYiLCJwYXRoIjoibWVkaWEvY2xpcHMvNjk3M2RiMGU5NDc2NDAwMjBjOWMyMmY3L21pa2UtbWNxdWFpZHMtc3R1ZGlvLWNvbXBvc2VyLTIwMjYtMS0yM19fMjEtMzMtMTgubXAzIn0=.mp3"><![CDATA[<p class="post_date">24 January 2026</p>
          
            <p><strong>Minimum Viable Management</strong></p>
          
          
            
              <p>David Yee, VP of Engineering at The New York Times and head of its new AI platforms and products mission, joins Mike McQuaid and Neha Batra for a candid, behind-the-scenes conversation about why institutions are built to resist change and what to do about it. They dig into hidden norms, choosing the right battles, translating “how things really work” and creating stability for teams while you deliberately destabilize the system just enough to move it forward.</p>
            
          
          
            <p><a href="https://api.riverside.fm/hosting-analytics/media/c0744bf875ca2fe6763dbe3f1a608bea63c7f091e4429bfa638ba97bd3d5a4fc/eyJlcGlzb2RlSWQiOiIwMGZmNDJmZC0yMGE1LTQ3MDUtYmZhMi01MzYzODA2NmQzZmEiLCJwb2RjYXN0SWQiOiI4NWZlZTgzNC1iMWNhLTRlYTItOGEwNy1lMjUyMDdmODQyZGYiLCJhY2NvdW50SWQiOiI2OGQ2YjhlNjU2NDE2OTA2NGI2MzAxMjYiLCJwYXRoIjoibWVkaWEvY2xpcHMvNjk3M2RiMGU5NDc2NDAwMjBjOWMyMmY3L21pa2UtbWNxdWFpZHMtc3R1ZGlvLWNvbXBvc2VyLTIwMjYtMS0yM19fMjEtMzMtMTgubXAzIn0=.mp3">Download audio</a></p>]]></content>

      
      
      
      

      <author>
        <name>Mike McQuaid</name>
        
          <email>mike@mikemcquaid.com</email>
        
        
          <uri>https://mikemcquaid.com</uri>
        
      </author>

      
      
        <summary type="html"><![CDATA[David Yee, VP of Engineering at The New York Times and head of its new AI platforms and products mission, joins Mike McQuaid and Neha Batra for a candid, behind-the-scenes conversation about why institutions are built to resist change and what to do about it. They dig into hidden norms, choosing the right battles, translating “how things really work” and creating stability for teams while you deliberately destabilize the system just enough to move it forward.]]></summary>
      

      
      

      
      
    </entry>
  
</feed>
