<?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://fzakaria.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://fzakaria.com/" rel="alternate" type="text/html" /><updated>2026-07-09T14:11:16-07:00</updated><id>https://fzakaria.com/feed.xml</id><title type="html">Farid Zakaria’s Blog</title><subtitle>I&apos;m a software engineer, father and wishful amateur surfer. If you&apos;ve come seeking my political views, you&apos;ve found the wrong &lt;a href=&quot;https://fareedzakaria.com/&quot;&gt;Fareed&lt;/a&gt;.</subtitle><entry><title type="html">Who does Anubis actually stop?</title><link href="https://fzakaria.com/2026/07/09/who-does-anubis-actually-stop" rel="alternate" type="text/html" title="Who does Anubis actually stop?" /><published>2026-07-09T12:21:00-07:00</published><updated>2026-07-09T12:21:00-07:00</updated><id>https://fzakaria.com/2026/07/09/who-does-anubis-actually-stop</id><content type="html" xml:base="https://fzakaria.com/2026/07/09/who-does-anubis-actually-stop"><![CDATA[<p>I have been working on a patch to the Linux kernel to support <code class="language-plaintext highlighter-rouge">$ORIGIN</code> for the interpreter (<code class="language-plaintext highlighter-rouge">PT_INTERP</code>) via bpf in <code class="language-plaintext highlighter-rouge">binfmt_misc</code> [<a href="https://lore.kernel.org/linux-mm/20260622043934.179879-1-farid.m.zakaria@gmail.com/T/#t">thread</a>].</p>

<p>Of course I’m leveraging an LLM to help me do this! To pre-seed the context of the LLM, I asked it to read the <a href="https://lore.kernel.org/">https://lore.kernel.org/</a> thread.</p>

<p><a href="/assets/images/anubis-challenge.png"><img src="/assets/images/anubis-challenge_50p.png" alt="Anubis challenge page" /></a></p>

<p>Uh oh. Looks like they have adopted <a href="https://github.com/TecharoHQ/anubis">Anubis</a>, which is an HTTP proxy that requires <em>proof-of-work</em> before allowing access to the resource.</p>

<p>Did this really do anything?</p>

<p>Unfortunately, no.</p>

<p>My AI diligently came up with <strong>anubis-fetch</strong>, which you can find at <a href="https://github.com/fzakaria/anubis-fetch">https://github.com/fzakaria/anubis-fetch</a>. The tool tries to natively solve the proof of work or, as a last resort, will launch Chromium to visit the URL.</p>

<blockquote>
  <p>This tool also impersonates a real Chrome TLS/JA3 fingerprint natively via <a href="https://req.cool/">req</a> so it clears passive Cloudflare blocking too. ☝️</p>
</blockquote>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">#</span><span class="w"> </span>HTML to stdout
<span class="gp">$</span><span class="w"> </span>anubis-fetch https://lore.kernel.org/linux-mm/some-thread/T/
<span class="go">
</span><span class="gp">#</span><span class="w"> </span>readable plain text
<span class="gp">$</span><span class="w"> </span>anubis-fetch <span class="nt">--text</span> https://lore.kernel.org/linux-mm/some-thread/T/
</code></pre></div></div>

<p>So who did we stop?</p>

<p>The exact adversary Anubis targets defeats it trivially.</p>

<p>The whole use of Anubis feels regressive and marginalizes those without access to “good” AI.</p>

<p>For a scraper, solving the Anubis challenge is a one-time, amortized-to-zero cost since the cookie can be cached and reused. For a human, it’s seconds of spinner, battery drain on every fresh visit. They can’t amortize anything amongst each other.</p>

<p>This “regressive tax” is paid even more so by those with weaker devices or who access the content on their phone. Clients that don’t leverage JavaScript (e.g., text browsers (w3m/lynx), screen readers, RSS readers) are completely left out.</p>

<p>Did deploying Anubis stop any of the aforementioned bot-farms or are they mildly inconvenienced when they had to augment their bots to support a new proof of work solution briefly?</p>

<p>The irony is that Anubis’s goal is to stop AI but it was incredibly easy for AI to circumvent it and yet the cost to humans and an open web remains.</p>

<p>With the presumption Anubis is now a regressive tax, how much does it cost us?</p>

<p>Every number here is a rough estimate. This is not a environmental argument at all since the bot-farmers and AI tools themselves are using many orders of magnitude more energy. Nevertheless, it’s interesting to see how much time is spent doing proof-of-work challenges that marginalize people.</p>

<blockquote>
  <p>Difficulty <code class="language-plaintext highlighter-rouge">d</code> is the number of leading zero <em>hex</em> characters the hash must have, so the expected work per solve is <code class="language-plaintext highlighter-rouge">W = 16^d</code> hashes.</p>
</blockquote>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Difficulty</th>
      <th style="text-align: left">Hashes / solve</th>
      <th style="text-align: left">Go native</th>
      <th style="text-align: left">Browser JS</th>
      <th style="text-align: left">Felt wall-clock</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left"><strong>4</strong></td>
      <td style="text-align: left">65,536</td>
      <td style="text-align: left">~1.3 ms</td>
      <td style="text-align: left">~130 ms</td>
      <td style="text-align: left">~1–5 s</td>
    </tr>
    <tr>
      <td style="text-align: left">5</td>
      <td style="text-align: left">1,048,576</td>
      <td style="text-align: left">~20 ms</td>
      <td style="text-align: left">~2 s</td>
      <td style="text-align: left">~5–15 s</td>
    </tr>
  </tbody>
</table>

<p><em>Difficulty 4 is the common default. Rates assumed: ~50 MH/s native (Go), ~0.5 MH/s in-browser JS; “felt” wall-clock includes page load, the worker, and the reload.</em></p>

<p>Let <code class="language-plaintext highlighter-rouge">C</code> be the number of Anubis challenge-solves per day, worldwide. Assume a felt time of <code class="language-plaintext highlighter-rouge">t = 2 s</code> and device energy <code class="language-plaintext highlighter-rouge">E = 20 J</code> per solve (screen + CPU).</p>

<ul>
  <li><strong>Human-time / year</strong> = <code class="language-plaintext highlighter-rouge">C × t × 365 / 3.15×10⁷</code></li>
  <li><strong>Energy / year (kWh)</strong> = <code class="language-plaintext highlighter-rouge">C × E × 365 / 3.6×10⁶</code></li>
</ul>

<table>
  <thead>
    <tr>
      <th style="text-align: left"><code class="language-plaintext highlighter-rouge">C</code> (solves/day)</th>
      <th style="text-align: left">Human-time wasted / year</th>
      <th style="text-align: left">Energy / year</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">1 M</td>
      <td style="text-align: left"><strong>~23 person-years</strong></td>
      <td style="text-align: left">~2 MWh</td>
    </tr>
    <tr>
      <td style="text-align: left">10 M</td>
      <td style="text-align: left"><strong>~230 person-years</strong></td>
      <td style="text-align: left">~20 MWh</td>
    </tr>
    <tr>
      <td style="text-align: left">100 M</td>
      <td style="text-align: left"><strong>~2,300 person-years</strong></td>
      <td style="text-align: left">~200 MWh</td>
    </tr>
  </tbody>
</table>

<p>Collectively we are wasting an impressive amount of time waiting for access to websites; time we didn’t spend before the AI era. As a human, time is precious and finite to me, whereas to a robot it is not.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I have been working on a patch to the Linux kernel to support $ORIGIN for the interpreter (PT_INTERP) via bpf in binfmt_misc [thread].]]></summary></entry><entry><title type="html">A TacoSprint 2026 Retrospective</title><link href="https://fzakaria.com/2026/06/29/a-tacosprint-2026-retrospective" rel="alternate" type="text/html" title="A TacoSprint 2026 Retrospective" /><published>2026-06-29T07:46:00-07:00</published><updated>2026-06-29T07:46:00-07:00</updated><id>https://fzakaria.com/2026/06/29/a-tacosprint-2026-retrospective</id><content type="html" xml:base="https://fzakaria.com/2026/06/29/a-tacosprint-2026-retrospective"><![CDATA[<p>This is my retrospective of <a href="https://tacosprint.org/">TacoSprint 2026</a> that took place in June 2026 at La Saladita, Guerrero, Mexico.</p>

<p>For a while now, I have watched from the sidelines as Nixers around the world gathered for sprints: <a href="https://oceansprint.org/">OceanSprint</a>, <a href="https://thaigersprint.org/">ThaigerSprint</a>, <a href="https://saltsprint.org/">SaltSprint</a>, <a href="https://transylvaniasprint.org/">TransylvaniaSprint</a>, <a href="https://aurorasprint.com/">AuroraSprint</a> and <a href="https://nix.camp/">NixCamp</a>.</p>

<blockquote>
  <p>Wow, we Nixers sure do like our sprints! All of them also happen to be in Europe or East-Asia.</p>
</blockquote>

<p>With an upcoming fourth baby on the way, I figured it was now-or-never to put words into action. I messaged <a href="https://github.com/domenkozar">@domen</a>, who organizes OceanSprint every year, and asked if he’d be interested in helping me set up the first sprint in North America. Domen is an avid surfer, a recurring theme in his OceanSprints, so I appealed to his inner-surfer and we spec’d out some places in North America that were both cost-effective <em>and</em> had ample, amazing surf 🏄.</p>

<p>I had already been to the <a href="https://www.bontraveler.com/troncones-mexico/">Troncones</a> and the <a href="https://thesurfatlas.com/surfing-mexico/playa-la-saladita/">La Saladita</a> area, so my prior experience removed a large vector of the unknown. It seemed like a no-brainer. Domen was already going to be in South America in June, so the timing lined up nicely (+ summer is the swell season there!).</p>

<p>We set to work standing up a website and trying to attract sponsorship and attendees.</p>

<p>🦗</p>

<p>This was probably the hardest part of organizing a brand-new sprint. We had far lower turnout for registration and sponsorship than I foresaw. Several people responded on our application form, or told us directly, that they were unsure about the safety of visiting Mexico, since the US Department of State had it under a travel advisory. Despite my best efforts to soothe everyone’s fears, it remained a real hindrance.</p>

<blockquote class="alert alert-note">
  <p><strong>Note</strong>
For those still on the fence for next year: the area felt extremely safe. We rented a house in a fairly secluded stretch that caters almost entirely to surfers. At no point did anyone feel uncomfortable or unsafe.</p>
</blockquote>

<p>Getting there was its own small adventure. Flights were unusually challenging to book thanks to the World Cup soaking up demand across the region. The most dramatic casualty was Alex (<a href="https://github.com/adeci">@adeci</a>), who managed to completely miss his connecting flight and arrived three days late. To his credit, he showed up in great spirits and slotted right back in to hacking with the group like nothing happened.</p>

<p>Once everyone was settled, we fell into a rhythm that I can only describe as <em>suspiciously sustainable</em>:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">while</span> <span class="p">(</span><span class="n">sprint</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">surf</span><span class="p">();</span>       <span class="c1">// ~6am – 9am</span>
  <span class="n">breakfast</span><span class="p">();</span>
  <span class="n">hack</span><span class="p">();</span>
  <span class="n">lunch</span><span class="p">();</span>
  <span class="n">hack</span><span class="p">();</span>
  <span class="n">surf</span><span class="p">();</span>       <span class="c1">// ~5pm – 8pm</span>
  <span class="n">dinner</span><span class="p">();</span>
  <span class="n">hack</span><span class="p">();</span>
  <span class="n">sleep</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>It was amazing to bookend each day with a surf at La Saladita’s left point break. Surfing for me lets me enter <em>flow state</em> very similar to when I am deep in thought hacking-away. It helped clear through a lot of built-up gunk and I often returned back with a clear intention or solution to a problem I had been working on.</p>

<p>One of the more unexpectedly wonderful parts of the trip was the meal preparation from Gladys, our local cook, who pretty much cooked for us three times a day. We were extremely well-fed, which let us focus on the Nix-hacking and motivated me to make sure I kept up with the surfing to put off any weight gain 🫠.</p>

<p>The website will be updated to have a more formal summary of every contribution we managed to put forward and their current status however it was amazing to see how much work a group of nine people can put forward in a single week with a combined mission and passion for an ecosystem. Our work spanned dynamic linking, package relocatability, peer-to-peer remote builds, faster module systems, shrinking the OCaml runtime closure and cross-distribution packaging.</p>

<p>A few of my own threads, if you want to go deeper:</p>

<ul>
  <li><a href="/2026/06/25/guixpkgs-every-guix-package-as-a-nix-flake">GuixPkgs: every Guix package, as a Nix flake</a></li>
  <li><a href="/2026/06/22/hijacking-elf-entry-points-for-nixos-compatibility-or-wtf-is-wrap-buddy">Hijacking ELF entry points for NixOS compatibility, or wtf is wrap-buddy</a></li>
  <li><a href="/2026/06/21/nix-needs-relocatable-binaries">Nix needs relocatable binaries</a></li>
</ul>

<p>LLM-based agents featured prominently throughout. We were fortunate to have <a href="https://ghuntley.com/">Geoff Huntley</a> with us, who is quite the <em>AI-maximizer</em>, spiritually guiding us and offering us some SOTA insight in how we might want to explore leveraging AI.</p>

<p>Alan (<a href="https://github.com/alurm">@alurm</a>), had the greatest idea for us to put together an academic style trip report. We worked together on the paper and the result is <em>Attention, Nix and Tacos Is All You Need</em>, a loving parody of a certain famous paper.</p>

<p>An arXiv submission is coming, but in the meantime you can read it below or <a href="/assets/pdfs/Attention_Nix_and_Tacos_is_All_You_Need.pdf">download it here</a>.</p>

<object data="/assets/pdfs/Attention_Nix_and_Tacos_is_All_You_Need.pdf" type="application/pdf" width="100%" height="600px">
  <p>Your browser doesn't support embedded PDFs. You can <a href="/assets/pdfs/Attention_Nix_and_Tacos_is_All_You_Need.pdf">download it here</a> instead.</p>
</object>

<p>We already agreed to organize the same sprint next year. I can’t wait. This was <strong>literally</strong> the most enjoyable thing I’ve ever done as it combined my two passions (surfing &amp; hacking) in a way I honestly did not think was possible all while producing a ton of value to the Nix ecosystem.</p>

<p>For a different vantage point, please check out the retrospectives from my fellow attendees!</p>

<ul>
  <li><a href="https://alurm.github.io/blog/2026-06-26-tacosprint.html">Alan Urmancheev</a></li>
  <li><a href="https://jrdsgl.com/nix-taco-sprint-2026/">Jared Siegel</a></li>
</ul>]]></content><author><name></name></author><summary type="html"><![CDATA[This is my retrospective of TacoSprint 2026 that took place in June 2026 at La Saladita, Guerrero, Mexico.]]></summary></entry><entry><title type="html">GuixPkgs: every Guix package, as a Nix flake</title><link href="https://fzakaria.com/2026/06/25/guixpkgs-every-guix-package-as-a-nix-flake" rel="alternate" type="text/html" title="GuixPkgs: every Guix package, as a Nix flake" /><published>2026-06-25T09:00:00-07:00</published><updated>2026-06-25T09:00:00-07:00</updated><id>https://fzakaria.com/2026/06/25/guixpkgs-every-guix-package-as-a-nix-flake</id><content type="html" xml:base="https://fzakaria.com/2026/06/25/guixpkgs-every-guix-package-as-a-nix-flake"><![CDATA[<p align="center">
  <img src="/assets/images/guixpkgs-logo.png" alt="GuixPkgs Logo" width="250" />
</p>

<p>I wrote earlier about what I believe to be an <em>absurd idea</em>,  <a href="/2026/06/05/the-guix-nix-abomination-leveraging-guix-derivations-in-nix">The Guix Nix Abomination</a>: a tool, <a href="https://github.com/fzakaria/guix-transfer">guix-transfer</a>, that takes <strong>any</strong> Guix derivation and rewrites it into a Nix derivation, and lets <code class="language-plaintext highlighter-rouge">nix-daemon</code> build it.</p>

<p>With this primitive in hand, I pondered what it would mean to <strong>import the entire Guix package set</strong> into Nix.</p>

<blockquote>
  <p>That means we could even build a <code class="language-plaintext highlighter-rouge">flake</code> that is all of Guix packages available for use.</p>
</blockquote>

<p>Well…. Hello <a href="https://github.com/fzakaria/guixpkgs">GuixPkgs</a>. 🤯</p>

<p><a href="https://github.com/NixOS/nixpkgs">Nixpkgs</a> is famously the largest package repository in the world. GuixPkgs makes it bigger by including in the <em>entire</em> GNU Guix package set so you can mix and match Guix and Nixpkgs packages in the same flake.</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
  <span class="nv">description</span> <span class="o">=</span> <span class="s2">"A project mixing Nix and Guix"</span><span class="p">;</span>

  <span class="nv">inputs</span> <span class="o">=</span> <span class="p">{</span>
    <span class="nv">nixpkgs</span><span class="o">.</span><span class="nv">url</span> <span class="o">=</span> <span class="s2">"github:NixOS/nixpkgs/nixos-unstable"</span><span class="p">;</span>
    <span class="nv">guixpkgs</span><span class="o">.</span><span class="nv">url</span> <span class="o">=</span> <span class="s2">"github:fzakaria/guixpkgs"</span><span class="p">;</span>
  <span class="p">};</span>

  <span class="nv">outputs</span> <span class="o">=</span> <span class="p">{</span> <span class="nv">self</span><span class="p">,</span> <span class="nv">nixpkgs</span><span class="p">,</span> <span class="nv">guixpkgs</span> <span class="p">}:</span>
  <span class="kd">let</span>
    <span class="nv">system</span> <span class="o">=</span> <span class="s2">"x86_64-linux"</span><span class="p">;</span>
    <span class="nv">pkgs</span> <span class="o">=</span> <span class="nv">nixpkgs</span><span class="o">.</span><span class="nv">legacyPackages</span><span class="o">.</span><span class="p">${</span><span class="nv">system</span><span class="p">};</span>
    <span class="nv">guixPkgs</span> <span class="o">=</span> <span class="nv">guixpkgs</span><span class="o">.</span><span class="nv">packages</span><span class="o">.</span><span class="p">${</span><span class="nv">system</span><span class="p">};</span>
  <span class="kn">in</span> <span class="p">{</span>
    <span class="nv">devShells</span><span class="o">.</span><span class="p">${</span><span class="nv">system</span><span class="p">}</span><span class="o">.</span><span class="nv">default</span> <span class="o">=</span> <span class="nv">pkgs</span><span class="o">.</span><span class="nv">mkShell</span> <span class="p">{</span>
      <span class="nv">buildInputs</span> <span class="o">=</span> <span class="p">[</span>
        <span class="nv">pkgs</span><span class="o">.</span><span class="nv">git</span>        <span class="c"># from Nixpkgs</span>
        <span class="nv">guixPkgs</span><span class="o">.</span><span class="nv">hello</span>  <span class="c"># from Guix, via GuixPkgs</span>
      <span class="p">];</span>
    <span class="p">};</span>
  <span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">❯ nix build github:fzakaria/guixpkgs#</span>hello
<span class="go">❯ ./result/bin/hello
Hello, world!
</span></code></pre></div></div>

<p>☝ Don’t forget, that <code class="language-plaintext highlighter-rouge">hello</code> is built from Guix’s source bootstrap, a 357-byte seed all the way up to GCC and glibc but it lands in <code class="language-plaintext highlighter-rouge">/nix/store</code> and behaves like any other Nix package. No <code class="language-plaintext highlighter-rouge">guix</code> required on the consuming side.</p>

<p>Is this just a joke or is there anything of value here?</p>

<p>Well, some packages only exist in Guix, notable many GNU Guile built software, like <a href="https://github.com/artyom-poptsov/guile-png">guile-png</a> that are now easily available in Nix. 🤷</p>

<p>How does it work?</p>

<ol>
  <li>Pins a Guix commit and uses <code class="language-plaintext highlighter-rouge">guix time-machine</code> to get derivations from <em>that exact</em> Guix thus decoupling the result from whatever <code class="language-plaintext highlighter-rouge">guix-daemon</code> version happens to be on the host.</li>
  <li>Dumps every package’s <code class="language-plaintext highlighter-rouge">.drv</code> and feeds them to <code class="language-plaintext highlighter-rouge">guix-transfer --disable-tests --emit-nix-dir pkgs</code>.</li>
  <li>Rebuilds the <code class="language-plaintext highlighter-rouge">by-name/</code> index and records the Guix channel + commit + timestamp in <code class="language-plaintext highlighter-rouge">guix-metadata.json</code>.</li>
</ol>

<p>Realising a Guix package under Nix recompiles Guix’s <strong>entire source bootstrap</strong>. That’s <em>hours</em> per closure. To skip it, GuixPkgs ships a <a href="https://www.cachix.org/">Cachix</a>, <code class="language-plaintext highlighter-rouge">cachix use guixpkgs</code>, binary cache that is included in the flake. Thank you <a href="https://github.com/domenkozar">@domenkozar</a> for sponsoring me with extra storage. 🙏</p>

<p>What’s next?</p>

<p>We can now do some truly horrendous evil stuff.
What about an overlay that replaces every package from Nixpkgs which one that exists in Guix? 😈</p>

<p>We can then build a NixOS machine where every package is the Guix equivalent 😱.</p>

<p>This was a really fun project to pursue during <a href="https://tacosprint.org">TacoSprint</a>.</p>

<p><a href="/assets/images/tacosprint_group.jpg"><img src="/assets/images/tacosprint_group_50p.jpg" alt="taco sprint group photo" /></a></p>]]></content><author><name></name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Hijacking ELF entry points for NixOS compatibility or WTF is wrap-buddy?</title><link href="https://fzakaria.com/2026/06/22/hijacking-elf-entry-points-for-nixos-compatibility-or-wtf-is-wrap-buddy" rel="alternate" type="text/html" title="Hijacking ELF entry points for NixOS compatibility or WTF is wrap-buddy?" /><published>2026-06-22T17:55:00-07:00</published><updated>2026-06-22T17:55:00-07:00</updated><id>https://fzakaria.com/2026/06/22/hijacking-elf-entry-points-for-nixos-compatibility-or-wtf-is-wrap-buddy</id><content type="html" xml:base="https://fzakaria.com/2026/06/22/hijacking-elf-entry-points-for-nixos-compatibility-or-wtf-is-wrap-buddy"><![CDATA[<p>We are part-way through <a href="https://tacosprint.org/">TacoSprint 2026</a> and a project that has inspired me has been the long-standing pursuit of producing <a href="/2026/06/21/nix-needs-relocatable-binaries">relocatable binaries</a> in Nix. This is something I’ve been <a href="https://discourse.nixos.org/t/making-runpath-redundant-for-nix/21631/12?u=fzakaria">discussing since as early as 2022</a>.</p>

<p><a href="/assets/images/tacosprint_photo.webp"><img src="/assets/images/tacosprint_photo_50p.webp" alt="photo us hacking at tacosprint" /></a></p>

<p>We’ve made pretty great headway! 🥳</p>

<p>I posted a <a href="https://lore.kernel.org/linux-mm/20260622043934.179879-1-farid.m.zakaria@gmail.com/T/#t">proposal to the Linux kernel</a> mailing list to add support for <code class="language-plaintext highlighter-rouge">$ORIGIN</code> to <code class="language-plaintext highlighter-rouge">DT_INTERP</code>, which will allow for resolving the interpreter relatively.</p>

<p>I also submitted <a href="https://github.com/NixOS/nixpkgs/pull/534339">PR#534339</a> to <a href="https://github.com/NixOS/nixpkgs">nixpkgs</a> which improves the <code class="language-plaintext highlighter-rouge">RUNPATH</code> generation and shrinking by modifying them to leverage <code class="language-plaintext highlighter-rouge">$ORIGIN</code> as well. This needs no new Linux kernel support and will make Nix derivations <em>a teeny</em> bit more relocatable.</p>

<p>Throughout this investigation, I was informed about similar efforts via <a href="https://github.com/Mic92/wrap-buddy">wrap-buddy</a> by the venerable <a href="https://github.com/Mic92">Mic92</a>.</p>

<p>I opened the GitHub project and I have to admit, I did not quite understand it. Jörg is an amazingly prolific and technical developer, and despite my knowledge of the space, it took me a while to understand the <del>craziness</del> beauty of what was being done.</p>

<p>So, <em>wtf is wrap-buddy</em>?</p>

<p>Nix is all about explicit dependencies and it leverages this with techniques like <code class="language-plaintext highlighter-rouge">RUNPATH</code> on the ELF binary. This all works for newly minted code, but if you try to download any precompiled binary on your NixOS machine, you’ll hit an error for a myriad of reasons. One of the biggest being that the dynamic linker/interpreter, <code class="language-plaintext highlighter-rouge">/lib64/ld-linux-x86-64.so.2</code>, does not exist on NixOS.</p>

<p>We would love to compile everything from source, but the reality is that plenty of software people want to use is <em>closed</em>. In order to allow that to work on NixOS machines, derivations may <em>patch</em> the ELF files with <a href="https://github.com/nixos/patchelf">patchelf</a> setting things like <code class="language-plaintext highlighter-rouge">RUNPATH</code> and <code class="language-plaintext highlighter-rouge">DT_INTERP</code> to Nix-friendly paths.</p>

<p>In some rare cases, however, that <strong>doesn’t</strong> work. The documentation in <code class="language-plaintext highlighter-rouge">wrap-buddy</code> claims:</p>

<blockquote>
  <p><a href="https://nixos.org/manual/nixpkgs/stable/#setup-hook-autopatchelfhook">autoPatchelfHook</a> can be error-prone and may break binaries that, have unusual ELF layouts.</p>
</blockquote>

<p>In these pathological cases, <code class="language-plaintext highlighter-rouge">wrap-buddy</code> is an alternative that takes over the startup of the binary to modify it at runtime. 🤯</p>

<p>Let’s take a look with a small example.
We can build a small C program linked against two shared libraries, <code class="language-plaintext highlighter-rouge">libfoo</code> and <code class="language-plaintext highlighter-rouge">libbar</code>, forcing a non-NixOS interpreter path:</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">main</span><span class="o">:</span> <span class="nf">main.c libfoo.so libbar.so</span>
	gcc <span class="nt">-I</span><span class="nb">.</span> <span class="nt">-L</span><span class="nb">.</span> <span class="nt">-Wl</span>,--dynamic-linker<span class="o">=</span>/lib64/ld-linux-x86-64.so.2 <span class="nt">-o</span> main main.c <span class="nt">-lfoo</span> <span class="nt">-lbar</span>
</code></pre></div></div>

<p>If we run this binary, it fails immediately because <code class="language-plaintext highlighter-rouge">/lib64/ld-linux-x86-64.so.2</code> doesn’t exist or it can’t resolve <code class="language-plaintext highlighter-rouge">libfoo.so</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> ./main
./main: error <span class="k">while </span>loading shared libraries: libfoo.so: cannot open shared object file...
</code></pre></div></div>

<p>Now we patch it using <code class="language-plaintext highlighter-rouge">wrap-buddy</code> pointing to our library paths:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> wrap-buddy <span class="nt">--paths</span> ./main <span class="nt">--libs</span> ./libfoo ./libbar
Using interpreter: /nix/store/57iz36553175g3178pvxjij8z5rcsd4n-glibc-2.42-61/lib/ld-linux-x86-64.so.2
64-bit stub: 407 bytes
32-bit stub: 441 bytes
Patching: ./main
  ELF class: 64-bit
  Original entry: 0x11a0 <span class="o">(</span>file offset: 0x11a0<span class="o">)</span>
  Available space at entry: 569 bytes
  Stub size: 407 bytes <span class="o">(</span>padded to 416<span class="o">)</span>
  Wrote config to ./.main.wrapbuddy
  Overwrote 416 bytes at entry point
  Converted PT_INTERP to PT_NULL
Patched: ./main
</code></pre></div></div>

<p>Now if we run our binary, <code class="language-plaintext highlighter-rouge">main</code>, we see that it works:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> ./main
Starting C application...
Hello from libfoo!
Hello from libbar!
</code></pre></div></div>

<p>What did it do? 🤔</p>

<p>First off, it copies the first 416 bytes of our program code into a hidden file named <code class="language-plaintext highlighter-rouge">.main.wrapbuddy</code>.</p>

<p>Let’s peek at the original binary and the instructions for <code class="language-plaintext highlighter-rouge">_start</code>:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> radare2 <span class="nt">-q</span> <span class="nt">-c</span> <span class="s2">"e asm.functions=false; e asm.var=false; e asm.lines=false; e asm.xrefs=false; aa; pd 40 @ entry0"</span> main.orig
  <span class="p">;</span><span class="nt">--</span> _start:
0x000011a0      f30f1efa       endbr64
0x000011a4      31ed           xor ebp, ebp
0x000011a6      4989d1         mov r9, rdx                             <span class="p">;</span> arg3
0x000011a9      5e             pop rsi
0x000011aa      4889e2         mov rdx, rsp
0x000011ad      4883e4f0       and rsp, 0xfffffffffffffff0
0x000011b1      50             push rax
0x000011b2      54             push rsp
0x000011b3      4531c0         xor r8d, r8d
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">wrap-buddy</code> saves those starting 416 bytes to the hidden file <code class="language-plaintext highlighter-rouge">.main.wrapbuddy</code>. The configuration file format starts with a 22-byte header, followed by the interpreter string (83 bytes) and <code class="language-plaintext highlighter-rouge">RUNPATH</code> string (442 bytes), placing our saved original instructions at offset 547 (<code class="language-plaintext highlighter-rouge">0x223</code>):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> radare2 <span class="nt">-q</span> <span class="nt">-a</span> x86 <span class="nt">-b</span> 64 <span class="nt">-c</span> <span class="s2">"pd 10 @ 547"</span> .main.wrapbuddy
0x00000223      f30f1efa       endbr64
0x00000227      31ed           xor ebp, ebp
0x00000229      4989d1         mov r9, rdx
0x0000022c      5e             pop rsi
0x0000022d      4889e2         mov rdx, rsp
0x00000230      4883e4f0       and rsp, 0xfffffffffffffff0
0x00000234      50             push rax
0x00000235      54             push rsp
0x00000236      4531c0         xor r8d, r8d
0x00000239      31c9           xor ecx, ecx
</code></pre></div></div>

<p>Next, it clears our <code class="language-plaintext highlighter-rouge">PT_INTERP</code> to <code class="language-plaintext highlighter-rouge">PT_NULL</code> so the Linux kernel thinks it’s a statically linked binary and boots it directly:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; readelf -a main.orig | grep INTERP
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318

&gt; readelf -a main | grep NULL
  NULL           0x0000000000000318 0x0000000000000318 0x0000000000000318
</code></pre></div></div>

<p>Lastly, it overwrites our entrypoint with that <em>small stub</em> (416 bytes). We can see in the disassembly that <code class="language-plaintext highlighter-rouge">entry0</code> immediately redirects and calls <code class="language-plaintext highlighter-rouge">stub_main</code> now:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> radare2 <span class="nt">-q</span> <span class="nt">-c</span> <span class="s2">"e asm.functions=false; e asm.var=false; e asm.lines=false; e asm.xrefs=false; aa; af- 0x1203; f- sym.register_tm_clones; f stub_main @ 0x120f; pd 4 @ entry0; s entry0; so 3; s </span><span class="se">\$</span><span class="s2">ij; pd 40"</span> main
  <span class="p">;</span><span class="nt">--</span> _start:
0x000011a0      4831ed         xor rbp, rbp
0x000011a3      4889e7         mov rdi, rsp
0x000011a6      4883e4f0       and rsp, 0xfffffffffffffff0
0x000011aa      e860000000     call stub_main
<span class="p">;</span><span class="nt">--</span> stub_main:
0x0000120f      55             push rbp
0x00001210      b802000000     mov eax, 2
0x00001215      31f6           xor esi, esi
0x00001217      4889e5         mov rbp, rsp
0x0000121a      53             push rbx
0x0000121b      4889fb         mov rbx, rdi
0x0000121e      4881ec9800..   sub rsp, 0x98
</code></pre></div></div>

<p>Why all this complexity?
What is <code class="language-plaintext highlighter-rouge">stub_main</code> doing?</p>

<p>The goal of <code class="language-plaintext highlighter-rouge">stub_main</code> is to find a known custom loader, <code class="language-plaintext highlighter-rouge">loader.bin</code>, which will help us finish all the dynamic linking.</p>

<p>The custom loader gets even more nuanced and low-level. It would be a disservice to try and completely go over everything it does, and at this point the <a href="https://github.com/Mic92/wrap-buddy/blob/ab9f7fdf2012007d550293af688a67e11048528c/README.md">README</a> does a fairly good job.</p>

<p>At a high level:</p>

<ol>
  <li>It reads the saved original bytes from the <code class="language-plaintext highlighter-rouge">.main.wrapbuddy</code> file and copies the original bytes back over our stub in memory. To any observer, the binary is now completely clean and resembles the original.</li>
  <li>It injects the custom <code class="language-plaintext highlighter-rouge">RUNPATH</code> by creating a brand new dynamic section in memory and populates it with the <code class="language-plaintext highlighter-rouge">DT_RUNPATH</code> containing our library search paths that we stored in <code class="language-plaintext highlighter-rouge">.main.wrapbuddy</code>.</li>
  <li>It loads the real NixOS interpreter into memory.</li>
  <li>It rewrites the kernel’s stack metadata (auxiliary vector pointers like <code class="language-plaintext highlighter-rouge">AT_BASE</code>, <code class="language-plaintext highlighter-rouge">AT_PHDR</code>, and <code class="language-plaintext highlighter-rouge">AT_ENTRY</code>) to trick the native loader (<code class="language-plaintext highlighter-rouge">ld.so</code>) into believing it was loaded natively by the kernel.</li>
  <li>Finally, it jumps to the entry point of the NixOS interpreter.</li>
</ol>

<p>The NixOS dynamic linker takes over, uses the <code class="language-plaintext highlighter-rouge">RUNPATH</code> to resolve <code class="language-plaintext highlighter-rouge">libfoo.so</code> and <code class="language-plaintext highlighter-rouge">libbar.so</code>. We can now run the application using the restored original entry point with everything resolved.</p>

<p>Magic. Wizard. <a href="https://github.com/Mic92">Mic92</a>. 🧙</p>]]></content><author><name></name></author><summary type="html"><![CDATA[We are part-way through TacoSprint 2026 and a project that has inspired me has been the long-standing pursuit of producing relocatable binaries in Nix. This is something I’ve been discussing since as early as 2022.]]></summary></entry><entry><title type="html">Nix needs relocatable binaries</title><link href="https://fzakaria.com/2026/06/21/nix-needs-relocatable-binaries" rel="alternate" type="text/html" title="Nix needs relocatable binaries" /><published>2026-06-21T10:19:00-07:00</published><updated>2026-06-21T10:19:00-07:00</updated><id>https://fzakaria.com/2026/06/21/nix-needs-relocatable-binaries</id><content type="html" xml:base="https://fzakaria.com/2026/06/21/nix-needs-relocatable-binaries"><![CDATA[<blockquote>
  <p>This is my problem statement and proposal for a <a href="https://tacosprint.org/">TacoSprint 2026</a> project 🏄.</p>
</blockquote>

<p>Nix, or <em>store-based systems</em>, are a class of package managers that use a well-defined prefix to store all packages. This can be <code class="language-plaintext highlighter-rouge">/nix/store</code> for Nix or <code class="language-plaintext highlighter-rouge">/gnu/store</code> for Guix.</p>

<p>This is simple. It makes <em>rewriting</em> paths to binaries or libraries easy. Derivations only need to <code class="language-plaintext highlighter-rouge">sed</code> the strings with the full store-path; <code class="language-plaintext highlighter-rouge">/bin/bash</code> becomes <code class="language-plaintext highlighter-rouge">/nix/store/gik3rh1vz2jlgnifb9dh6vc6sxwwz9jj-bash-5.3p9/bin/bash</code> for instance.</p>

<p>What if you wanted a different path, one not prefixed at the root <code class="language-plaintext highlighter-rouge">/</code> ?</p>

<p>This could be desirable if you don’t have Nix installed already or are missing necessary permissions – “rootless Nix”.</p>

<p>Well, Nix already lets you specify a different store-path today <em>but there is a catch!</em></p>

<p>Let’s take a look at a simple example.
We can build <code class="language-plaintext highlighter-rouge">hello</code> two different ways.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> nix build nixpkgs#hello

<span class="o">&gt;</span> nix build <span class="nt">--store</span> /tmp/fzakaria/store nixpkgs#hello
</code></pre></div></div>

<p>The first command builds and installs <code class="language-plaintext highlighter-rouge">hello</code> at <code class="language-plaintext highlighter-rouge">/nix/store/zi2bj2hlavv8q743li2s9diqbcpmrf9b-hello-2.12.3/</code> and the second at <code class="language-plaintext highlighter-rouge">/tmp/fzakaria/store/nix/store/zi2bj2hlavv8q743li2s9diqbcpmrf9b-hello-2.12.3/</code> using <code class="language-plaintext highlighter-rouge">chroot</code> and mount namespaces.</p>

<p>Notice both have the same hash <code class="language-plaintext highlighter-rouge">zi2bj2hlavv8q743li2s9diqbcpmrf9b</code>.</p>

<p><strong>This is important.</strong> By keeping the hash the same, we can leverage the precomputed derivations from binary substituters like <a href="https://cache.nixos.org">https://cache.nixos.org</a>.</p>

<p>Ok, so what’s missing?</p>

<p>If you are using tools like <a href="https://bazel.build/">Bazel</a> or <a href="https://buck2.build/">Buck2</a> they likely already employ their own sandboxing via namespacing for builds. Integrating Nix into these ecosystems becomes incredibly impractical because we run into nested user namespace and mount restrictions.</p>

<p>We can ask <code class="language-plaintext highlighter-rouge">Nix</code> to use an alternate store prefix, <em>without chroot and mount namespaces</em> but it has a big gap.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> <span class="nv">XDG_CACHE_HOME</span><span class="o">=</span>/tmp/fzakaria/cache <span class="se">\</span>
nix <span class="nb">eval</span> <span class="nt">--store</span> <span class="s1">'local?store=/tmp/fzakaria/store&amp;state=/tmp/fzakaria/state&amp;log=/tmp/fzakaria/log'</span> <span class="se">\</span>
<span class="nt">--raw</span> nixpkgs#hello.outPath
/tmp/fzakaria/store/qv3fhi1j9gh27fyds5n5b16yia8i6zn5-hello-2.12.3
</code></pre></div></div>

<p>The hash is now <code class="language-plaintext highlighter-rouge">qv3fhi1j9gh27fyds5n5b16yia8i6zn5</code> 😭</p>

<p>It’s even more disastrous. Changing this simple string cascade-invalidates the entire dependency graph. You are now waiting 4 hours for GCC to compile just so you can print “Hello World” from a different folder. 🫠</p>

<p>This means we cannot leverage the public cache. This gap is called out by the <a href="https://nix.dev/manual/nix/2.24/store/types/local-store">Nix documentation</a> today.</p>

<p>Does it have to be that way?</p>

<p>What if we could install Nix binaries <em>anywhere</em>, without using namespacing or <code class="language-plaintext highlighter-rouge">chroot</code>. Can we have our cake and eat it too? 🍰</p>

<p>Nix needs <strong>relocatable binaries</strong>.</p>

<p>The problem is that the store-prefix is part of the derivation itself so it affects the hash calculation.</p>

<p>We don’t have to specify the full store-prefix everywhere. What if we used relative paths ? 🤔</p>

<p>Let’s look at one place the full paths are written today in the binary via <code class="language-plaintext highlighter-rouge">RUNPATH</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> patchelf <span class="si">$(</span>nix build <span class="nt">--no-link</span> <span class="nt">--print-out-paths</span> nixpkgs#hello<span class="si">)</span>/bin/hello <span class="se">\</span>
            <span class="nt">--print-rpath</span>
/nix/store/57iz36553175g3178pvxjij8z5rcsd4n-glibc-2.42-61/lib
</code></pre></div></div>

<p>When this program runs, the dynamic linker looks at <code class="language-plaintext highlighter-rouge">RUNPATH</code> to find its shared dependencies.</p>

<p>The loader in Linux however natively supports the variable <code class="language-plaintext highlighter-rouge">$ORIGIN</code> which translates to “the directory containing the executable.” [<a href="https://man7.org/linux/man-pages/man8/ld.so.8.html">ref</a>]</p>

<p>We could instead write the <code class="language-plaintext highlighter-rouge">RUNPATH</code> to be <code class="language-plaintext highlighter-rouge">$ORIGIN/../../57iz36553175g3178pvxjij8z5rcsd4n-glibc-2.42-61/lib</code>.</p>

<p>If we did that then changing the store would cause no hashes to change. No recompilation. 🥳</p>

<p>Okay, so are we done?</p>

<p>Well, like most things the devil is in the details. 😈</p>

<p>Before the dynamic linker can read the <code class="language-plaintext highlighter-rouge">RUNPATH</code> to find the necessary libraries, the Linux kernel has to load the dynamic linker itself. This path is stored in a different ELF header called <code class="language-plaintext highlighter-rouge">PT_INTERP</code> (Program Interpreter).</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;</span> patchelf <span class="si">$(</span>nix build <span class="nt">--no-link</span> <span class="nt">--print-out-paths</span> nixpkgs#hello<span class="si">)</span>/bin/hello <span class="se">\</span>
        <span class="nt">--print-interpreter</span>
/nix/store/57iz36553175g3178pvxjij8z5rcsd4n-glibc-2.42-61/lib/ld-linux-x86-64.so.2
</code></pre></div></div>

<p>Unfortunately, the Linux Kernel does not support <code class="language-plaintext highlighter-rouge">$ORIGIN</code> in this field <em>as of today</em>.</p>

<p>We run into the exact same kernel limitation with the shebang line in scripts as well.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/nix/store/gik3rh1vz2jlgnifb9dh6vc6sxwwz9jj-bash-5.3p9/bin/bash</span>
<span class="nb">echo</span> <span class="s2">"Hello!"</span>
</code></pre></div></div>

<p>When we execute a script, the kernel parses the <code class="language-plaintext highlighter-rouge">#!</code> (shebang) and expects an absolute path. Support for <code class="language-plaintext highlighter-rouge">$ORIGIN</code> is also lacking as <em>as of today</em>.</p>

<p>We cannot use relative paths reliably here unless they are relative to the current working directory, which breaks the moment you run the script from anywhere else.</p>

<h3 id="how-do-we-get-there-️">How Do We Get There? 🗺️</h3>

<p>To achieve true relocatable binaries, we need to bypass these kernel limitations. <code class="language-plaintext highlighter-rouge">$ORIGIN</code> historically would never make sense for <code class="language-plaintext highlighter-rouge">PT_INTERP</code> in the Linux kernel because “Why would you want your dynamic linker to be found relative to the file!?”.</p>

<p>Nix has changed that assessment. There are a few ways we could attack this:</p>

<ol>
  <li>We could patch the Linux kernel so that <code class="language-plaintext highlighter-rouge">$ORIGIN</code> is supported in <code class="language-plaintext highlighter-rouge">PT_INTERP</code> and the shebang.</li>
  <li>We wrap every binary with a small static binary that computes its own location and then invokes the dynamic linker.</li>
  <li>We need to replace file locations to also leverage language-specific features for relative paths. For instance, in Python we can leverage <code class="language-plaintext highlighter-rouge">__file__</code> to access files relative to itself similar to <code class="language-plaintext highlighter-rouge">$ORIGIN</code>.</li>
</ol>

<p>I believe augmenting support in the Linux kernel is the right approach. The beauty of Nix is we can even patch the kernel today in any NixOS machine for this support.</p>

<p>As a final cherry on top, we can include additional metadata <code class="language-plaintext highlighter-rouge">relocatable = true;</code> on every derivation whether it’s <em>relocatable</em>. 🍒</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This is my problem statement and proposal for a TacoSprint 2026 project 🏄.]]></summary></entry><entry><title type="html">nix-build in under 100 lines</title><link href="https://fzakaria.com/2026/06/21/nix-build-in-under-100-lines" rel="alternate" type="text/html" title="nix-build in under 100 lines" /><published>2026-06-21T10:00:00-07:00</published><updated>2026-06-21T10:00:00-07:00</updated><id>https://fzakaria.com/2026/06/21/nix-build-in-under-100-lines</id><content type="html" xml:base="https://fzakaria.com/2026/06/21/nix-build-in-under-100-lines"><![CDATA[<p>I’ve said before that <a href="/2026/03/07/nix-is-a-lie-and-that-s-ok">Nix is a lie</a>, and that underneath the ceremony Nix is really just an <a href="/2026/06/05/the-guix-nix-abomination-leveraging-guix-derivations-in-nix">Input Output Machine</a>.</p>

<p>The <code class="language-plaintext highlighter-rouge">nix</code> daemon <em>feels</em> like a black box. You type <code class="language-plaintext highlighter-rouge">nix build</code> and somewhere behind a Unix socket a privileged process does inscrutable things, and out the other end pops a path in <code class="language-plaintext highlighter-rouge">/nix/store</code>. 🪄</p>

<p>What if I told you the part everyone thinks is magic and that turning a derivation into a store path is nearly an <em>exec</em> ?</p>

<p>Let’s reimplement <code class="language-plaintext highlighter-rouge">nix-build</code> in under 100 lines of Go.</p>

<p>First off, What is a derivation, really?</p>

<p>A derivation (<code class="language-plaintext highlighter-rouge">.drv</code>) is just a build plan. Let’s instantiate the most boring one imaginable.</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># hello.nix</span>
<span class="kr">derivation</span> <span class="p">{</span>
  <span class="nv">name</span> <span class="o">=</span> <span class="s2">"hello"</span><span class="p">;</span>
  <span class="nv">system</span> <span class="o">=</span> <span class="kr">builtins</span><span class="o">.</span><span class="nv">currentSystem</span><span class="p">;</span>
  <span class="nv">builder</span> <span class="o">=</span> <span class="s2">"/bin/sh"</span><span class="p">;</span>
  <span class="nv">args</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">"-c"</span> <span class="s2">"echo 'Hello World' &gt; $out"</span> <span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>nix derivation show <span class="si">$(</span>nix-instantiate hello.nix<span class="si">)</span>
</code></pre></div></div>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"derivations"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"gifgxsqfsjg8pxna1kv0nbzz1zvivs0b-hello.drv"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="nl">"args"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="s2">"-c"</span><span class="p">,</span><span class="w">
        </span><span class="s2">"echo 'Hello World' &gt; $out"</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"builder"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/bin/sh"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"env"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"builder"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/bin/sh"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hello"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"out"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/nix/store/ddmbmrgzcqqp0b8i9gmzav8zs8ch3176-hello"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"system"</span><span class="p">:</span><span class="w"> </span><span class="s2">"x86_64-linux"</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"inputs"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"drvs"</span><span class="p">:</span><span class="w"> </span><span class="p">{},</span><span class="w"> </span><span class="nl">"srcs"</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="p">},</span><span class="w">
      </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"hello"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"outputs"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"out"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"path"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ddmbmrgzcqqp0b8i9gmzav8zs8ch3176-hello"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"system"</span><span class="p">:</span><span class="w"> </span><span class="s2">"x86_64-linux"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">},</span><span class="w">
  </span><span class="nl">"version"</span><span class="p">:</span><span class="w"> </span><span class="mi">4</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>That’s the <em>whole</em> thing. A program to run (<code class="language-plaintext highlighter-rouge">builder</code> + <code class="language-plaintext highlighter-rouge">args</code>), an environment (<code class="language-plaintext highlighter-rouge">env</code>), the outputs it must produce, and the other derivations it depends on (<code class="language-plaintext highlighter-rouge">inputDrvs</code>), which in this case is empty. No magic 🪄.</p>

<p>So “realising” a derivation is just four steps:</p>

<ol>
  <li>Realise its <code class="language-plaintext highlighter-rouge">inputDrvs</code> first recursively. This <em>is</em> the build graph.</li>
  <li>Scrub the environment down to a known set of variables.</li>
  <li>Set <code class="language-plaintext highlighter-rouge">$out</code> to the store path the build must create.</li>
  <li><code class="language-plaintext highlighter-rouge">exec</code> the builder and check it produced <code class="language-plaintext highlighter-rouge">$out</code>.</li>
</ol>

<p>Here is the whole program in Go, in less than 100 lines (excluding comments 😉).
You can find the source <a href="https://gist.github.com/fzakaria/1be0657cc5f10df5e45d4ff1574b0273">here</a>.</p>

<blockquote class="alert alert-note">
  <p><strong>Note</strong>
I <em>cheated</em> a tiny bit and rather than writing a parser for Nix’s <a href="https://nix.dev/manual/nix/2.25/protocols/derivation-aterm">ATerm format</a>, I leveraged <code class="language-plaintext highlighter-rouge">nix show derivation</code> to get the JSON equivalent.</p>
</blockquote>

<details>
  <summary>build.go</summary>
  <div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">package</span> <span class="n">main</span>

<span class="k">import</span> <span class="p">(</span>
	<span class="s">"encoding/json"</span>
	<span class="s">"fmt"</span>
	<span class="s">"os"</span>
	<span class="s">"os/exec"</span>
	<span class="s">"strings"</span>
<span class="p">)</span>

<span class="k">const</span> <span class="n">store</span> <span class="o">=</span> <span class="s">"/nix/store"</span>

<span class="k">type</span> <span class="n">drv</span> <span class="k">struct</span> <span class="p">{</span>
	<span class="n">Args</span>    <span class="p">[]</span><span class="kt">string</span>          <span class="s">`json:"args"`</span>
	<span class="n">Builder</span> <span class="kt">string</span>            <span class="s">`json:"builder"`</span>
	<span class="n">Env</span>     <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">string</span> <span class="s">`json:"env"`</span>
	<span class="n">Inputs</span>  <span class="k">struct</span> <span class="p">{</span>
		<span class="n">Drvs</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">any</span> <span class="s">`json:"drvs"`</span>
	<span class="p">}</span> <span class="s">`json:"inputs"`</span>
	<span class="n">Outputs</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="k">struct</span> <span class="p">{</span>
		<span class="n">Path</span> <span class="kt">string</span> <span class="s">`json:"path"`</span>
	<span class="p">}</span> <span class="s">`json:"outputs"`</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">exists</span><span class="p">(</span><span class="n">path</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span> <span class="n">_</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">Stat</span><span class="p">(</span><span class="n">path</span><span class="p">);</span> <span class="k">return</span> <span class="n">err</span> <span class="o">==</span> <span class="no">nil</span> <span class="p">}</span>

<span class="c">// storePath makes a store path absolute; Nix's JSON uses bare basenames.</span>
<span class="k">func</span> <span class="n">storePath</span><span class="p">(</span><span class="n">p</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
	<span class="k">if</span> <span class="n">strings</span><span class="o">.</span><span class="n">HasPrefix</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="s">"/"</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">p</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">store</span> <span class="o">+</span> <span class="s">"/"</span> <span class="o">+</span> <span class="n">p</span>
<span class="p">}</span>

<span class="c">// loadDrv shells out to Nix to turn a .drv into JSON, then decodes it.</span>
<span class="k">func</span> <span class="n">loadDrv</span><span class="p">(</span><span class="n">path</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">error</span><span class="p">,</span> <span class="n">drv</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">data</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">exec</span><span class="o">.</span><span class="n">Command</span><span class="p">(</span><span class="s">"nix"</span><span class="p">,</span> <span class="s">"--extra-experimental-features"</span><span class="p">,</span> <span class="s">"nix-command"</span><span class="p">,</span>
		<span class="s">"derivation"</span><span class="p">,</span> <span class="s">"show"</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span><span class="o">.</span><span class="n">Output</span><span class="p">()</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span><span class="p">,</span> <span class="n">drv</span><span class="p">{}</span>
	<span class="p">}</span>
	<span class="k">var</span> <span class="n">doc</span> <span class="k">struct</span> <span class="p">{</span>
		<span class="n">Derivations</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="n">drv</span> <span class="s">`json:"derivations"`</span>
	<span class="p">}</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">json</span><span class="o">.</span><span class="n">Unmarshal</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">doc</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span><span class="p">,</span> <span class="n">drv</span><span class="p">{}</span>
	<span class="p">}</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">d</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">doc</span><span class="o">.</span><span class="n">Derivations</span> <span class="p">{</span>
		<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">d</span> <span class="c">// exactly one entry: the derivation we asked for</span>
	<span class="p">}</span>
	<span class="nb">panic</span><span class="p">(</span><span class="s">"no derivation found for "</span> <span class="o">+</span> <span class="n">path</span><span class="p">)</span>
<span class="p">}</span>

<span class="c">// realise ensures the derivation's output exists, building its inputs first,</span>
<span class="c">// and returns the default output's store path.</span>
<span class="k">func</span> <span class="n">realise</span><span class="p">(</span><span class="n">path</span> <span class="kt">string</span><span class="p">)</span> <span class="p">(</span><span class="kt">error</span><span class="p">,</span> <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
	<span class="n">err</span><span class="p">,</span> <span class="n">d</span> <span class="o">:=</span> <span class="n">loadDrv</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
	<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span><span class="p">,</span> <span class="s">""</span>
	<span class="p">}</span>
	<span class="n">out</span> <span class="o">:=</span> <span class="n">storePath</span><span class="p">(</span><span class="n">d</span><span class="o">.</span><span class="n">Outputs</span><span class="p">[</span><span class="s">"out"</span><span class="p">]</span><span class="o">.</span><span class="n">Path</span><span class="p">)</span>
	<span class="k">if</span> <span class="n">exists</span><span class="p">(</span><span class="n">out</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">out</span> <span class="c">// already built (this also memoises shared dependencies)</span>
	<span class="p">}</span>
	<span class="k">for</span> <span class="n">dep</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">d</span><span class="o">.</span><span class="n">Inputs</span><span class="o">.</span><span class="n">Drvs</span> <span class="p">{</span>
		<span class="n">realise</span><span class="p">(</span><span class="n">storePath</span><span class="p">(</span><span class="n">dep</span><span class="p">))</span> <span class="c">// recurse: dependencies before dependents</span>
	<span class="p">}</span>

	<span class="n">fmt</span><span class="o">.</span><span class="n">Fprintln</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">Stderr</span><span class="p">,</span> <span class="s">"building"</span><span class="p">,</span> <span class="n">out</span><span class="p">)</span>
	<span class="n">tmp</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">os</span><span class="o">.</span><span class="n">MkdirTemp</span><span class="p">(</span><span class="s">""</span><span class="p">,</span> <span class="s">"simple-nix-"</span><span class="p">)</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span><span class="p">,</span> <span class="s">""</span>
	<span class="p">}</span>
	<span class="k">defer</span> <span class="n">os</span><span class="o">.</span><span class="n">RemoveAll</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>

	<span class="c">// The build's entire environment: a few fixed vars, the derivation's own</span>
	<span class="c">// attributes, and one var per output (this is where $out comes from).</span>
	<span class="c">// These fixed variables and their values are specified by the Nix manual:</span>
	<span class="c">// https://github.com/NixOS/nix/blob/f8bb823a23bf6d62f4c8feb792a77702d7a49fe1/doc/manual/source/store/building.md?plain=1#L154</span>
	<span class="n">env</span> <span class="o">:=</span> <span class="k">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">string</span><span class="p">{</span>
		<span class="s">"PATH"</span><span class="o">:</span> <span class="s">"/path-not-set"</span><span class="p">,</span> <span class="s">"HOME"</span><span class="o">:</span> <span class="s">"/homeless-shelter"</span><span class="p">,</span>
		<span class="s">"NIX_STORE"</span><span class="o">:</span> <span class="n">store</span><span class="p">,</span> <span class="s">"NIX_BUILD_TOP"</span><span class="o">:</span> <span class="n">tmp</span><span class="p">,</span>
		<span class="s">"TMPDIR"</span><span class="o">:</span> <span class="n">tmp</span><span class="p">,</span> <span class="s">"TEMPDIR"</span><span class="o">:</span> <span class="n">tmp</span><span class="p">,</span> <span class="s">"TMP"</span><span class="o">:</span> <span class="n">tmp</span><span class="p">,</span> <span class="s">"TEMP"</span><span class="o">:</span> <span class="n">tmp</span><span class="p">,</span>
	<span class="p">}</span>
	<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">d</span><span class="o">.</span><span class="n">Env</span> <span class="p">{</span>
		<span class="n">env</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
	<span class="p">}</span>
	<span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">o</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">d</span><span class="o">.</span><span class="n">Outputs</span> <span class="p">{</span>
		<span class="n">env</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">storePath</span><span class="p">(</span><span class="n">o</span><span class="o">.</span><span class="n">Path</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="n">cmd</span> <span class="o">:=</span> <span class="n">exec</span><span class="o">.</span><span class="n">Command</span><span class="p">(</span><span class="n">d</span><span class="o">.</span><span class="n">Builder</span><span class="p">,</span> <span class="n">d</span><span class="o">.</span><span class="n">Args</span><span class="o">...</span><span class="p">)</span>
	<span class="n">cmd</span><span class="o">.</span><span class="n">Dir</span><span class="p">,</span> <span class="n">cmd</span><span class="o">.</span><span class="n">Stdout</span><span class="p">,</span> <span class="n">cmd</span><span class="o">.</span><span class="n">Stderr</span> <span class="o">=</span> <span class="n">tmp</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">Stderr</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">Stderr</span>
	<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">env</span> <span class="p">{</span>
		<span class="n">cmd</span><span class="o">.</span><span class="n">Env</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">cmd</span><span class="o">.</span><span class="n">Env</span><span class="p">,</span> <span class="n">k</span><span class="o">+</span><span class="s">"="</span><span class="o">+</span><span class="n">v</span><span class="p">)</span>
	<span class="p">}</span>

	<span class="k">if</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">cmd</span><span class="o">.</span><span class="n">Run</span><span class="p">();</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
		<span class="k">return</span> <span class="n">err</span><span class="p">,</span> <span class="s">""</span>
	<span class="p">}</span>

	<span class="k">if</span> <span class="o">!</span><span class="n">exists</span><span class="p">(</span><span class="n">out</span><span class="p">)</span> <span class="p">{</span>
		<span class="nb">panic</span><span class="p">(</span><span class="n">fmt</span><span class="o">.</span><span class="n">Sprintf</span><span class="p">(</span><span class="s">"builder did not produce %s"</span><span class="p">,</span> <span class="n">out</span><span class="p">))</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">out</span>
<span class="p">}</span>

<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">Args</span><span class="p">)</span> <span class="o">&lt;</span> <span class="m">2</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Fprintln</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">Stderr</span><span class="p">,</span> <span class="s">"usage: simple-nix &lt;file.drv&gt; ..."</span><span class="p">)</span>
		<span class="n">os</span><span class="o">.</span><span class="n">Exit</span><span class="p">(</span><span class="m">2</span><span class="p">)</span>
	<span class="p">}</span>
	<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">arg</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">os</span><span class="o">.</span><span class="n">Args</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="p">]</span> <span class="p">{</span>
		<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">realise</span><span class="p">(</span><span class="n">arg</span><span class="p">))</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>  </div>
</details>

<p>That’s it. Does it work?</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>go build <span class="nt">-o</span> simple-nix <span class="nb">.</span>

<span class="nv">$ </span>./simple-nix <span class="si">$(</span>nix-instantiate hello.nix<span class="si">)</span>
building /nix/store/ddmbmrgzcqqp0b8i9gmzav8zs8ch3176-hello
/nix/store/ddmbmrgzcqqp0b8i9gmzav8zs8ch3176-hello

<span class="nv">$ </span><span class="nb">cat</span> /nix/store/ddmbmrgzcqqp0b8i9gmzav8zs8ch3176-hello
Hello World
</code></pre></div></div>

<p>We can even build a real-world derivation.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./simple-nix <span class="si">$(</span>nix <span class="nb">eval </span>nixpkgs#hello <span class="nt">--raw</span><span class="si">)</span>

Using versionCheckHook
Running phase: unpackPhase
unpacking <span class="nb">source </span>archive /nix/store/wj7phsmi7ncidl8k00p489krqss7n9sd-hello-2.12.3.tar.gz
<span class="nb">source </span>root is hello-2.12.3
setting SOURCE_DATE_EPOCH to timestamp 1773804383 of file <span class="s2">"hello-2.12.3/ChangeLog"</span>
Running phase: patchPhase
Running phase: updateAutotoolsGnuConfigScriptsPhase
Updating Autotools / GNU config script to a newer upstream version: ./build-aux/config.sub
Updating Autotools / GNU config script to a newer upstream version: ./build-aux/config.guess
...
</code></pre></div></div>

<p>So what <em>is</em> missing?</p>

<p>Quite a lot, honestly <strong>but</strong> none of it is the part that turns a derivation into a path.</p>

<ul>
  <li><strong>Sandboxing</strong>: Nix runs the builder in a mount/network/PID namespaces for security and hermiticity.</li>
  <li><strong>The database</strong>: Nix records every valid path and its references in a SQLite db. We just check if the file exists.</li>
  <li><strong>Substitution</strong>: Nix asks a binary cache if the derivation was already built.</li>
  <li><strong>Everything else</strong>: Multiple output paths, support for fixed-output derivations (<code class="language-plaintext highlighter-rouge">fetchurl</code>), garbage collection, etc.</li>
</ul>

<p>The beauty of Nix is the derivation is a pure function. Getting the store path is not magic. It’s <code class="language-plaintext highlighter-rouge">exec</code> with a clean environment. Everything else, <em>mostly</em> is bookkeeping and security.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve said before that Nix is a lie, and that underneath the ceremony Nix is really just an Input Output Machine.]]></summary></entry><entry><title type="html">A trillion dollars</title><link href="https://fzakaria.com/2026/06/15/a-trillion-dollars" rel="alternate" type="text/html" title="A trillion dollars" /><published>2026-06-15T08:20:00-07:00</published><updated>2026-06-15T08:20:00-07:00</updated><id>https://fzakaria.com/2026/06/15/a-trillion-dollars</id><content type="html" xml:base="https://fzakaria.com/2026/06/15/a-trillion-dollars"><![CDATA[<blockquote>
  <p>This is not meant to be a political post.</p>
</blockquote>

<p>Headlines recently have been projecting Elon Musk’s net worth to hit $1 trillion USD.</p>

<p>Working in software, you inevitably come up against Jeff Dean’s <a href="https://colin-scott.github.io/personal_website/research/interactive_latency.html">latency numbers every programmer should know</a>.</p>

<p>The original post wasn’t just insightful for sharing the time costs of common I/O operations. By using the scale of one access pattern to contextualize the next order of magnitude, it really helped entrench the cost of these increasing access patterns in my mind.</p>

<p>Scale at increasing orders of magnitude is often difficult to comprehend. Although logarithmic graphs are useful for showing exponential growth or displaying vastly different scales on a single chart, they are easily misunderstood.</p>

<p>If we were to map 1 <strong>million</strong> USD to 1 <em>ns</em>, what are the matching parallels to I/O access patterns?</p>

<table>
  <thead>
    <tr>
      <th style="text-align: left">Latency Operation</th>
      <th style="text-align: left">Time</th>
      <th style="text-align: left">USD Equivalent</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: left">L1 cache reference</td>
      <td style="text-align: left">1 ns</td>
      <td style="text-align: left">$1,000,000</td>
    </tr>
    <tr>
      <td style="text-align: left">Branch mispredict</td>
      <td style="text-align: left">3 ns</td>
      <td style="text-align: left">$3,000,000</td>
    </tr>
    <tr>
      <td style="text-align: left">L2 cache reference</td>
      <td style="text-align: left">4 ns</td>
      <td style="text-align: left">$4,000,000</td>
    </tr>
    <tr>
      <td style="text-align: left">Mutex lock/unlock</td>
      <td style="text-align: left">17 ns</td>
      <td style="text-align: left">$17,000,000</td>
    </tr>
    <tr>
      <td style="text-align: left">Main memory reference</td>
      <td style="text-align: left">100 ns</td>
      <td style="text-align: left">$100,000,000</td>
    </tr>
    <tr>
      <td style="text-align: left">Read 1,000 ns sequentially from memory</td>
      <td style="text-align: left">3,000 ns (3 µs)</td>
      <td style="text-align: left">$3,000,000,000 (3 Billion)</td>
    </tr>
    <tr>
      <td style="text-align: left">SSD random read</td>
      <td style="text-align: left">16,000 ns (16 µs)</td>
      <td style="text-align: left">$16,000,000,000 (16 Billion)</td>
    </tr>
    <tr>
      <td style="text-align: left">Read 1 MB sequentially from memory</td>
      <td style="text-align: left">250,000 ns (250 µs)</td>
      <td style="text-align: left">$250,000,000,000 (250 Billion)</td>
    </tr>
    <tr>
      <td style="text-align: left">Round trip within same datacenter</td>
      <td style="text-align: left">500,000 ns (500 µs)</td>
      <td style="text-align: left">$500,000,000,000 (500 Billion)</td>
    </tr>
    <tr>
      <td style="text-align: left"><strong>Read 1 MB sequentially from SSD</strong></td>
      <td style="text-align: left"><strong>1,000,000 ns (1 ms)</strong></td>
      <td style="text-align: left"><strong>$1,000,000,000,000 (One Trillion)</strong></td>
    </tr>
  </tbody>
</table>

<p>I have seen similar graphics for representing wealth, but I decided to make my own – because <em>why not</em>.</p>

<p>Check it out: <a href="https://fzakaria.github.io/trillion-wut/">https://fzakaria.github.io/trillion-wut/</a> – <em>how fast can you scroll to the bottom?</em></p>

<p><a href="/assets/images/trillion_wut.png"><img src="/assets/images/trillion_wut_50p.png" alt="lol wut example" /></a></p>

<p>You can find the source available at <a href="https://github.com/fzakaria/trillion-wut">https://github.com/fzakaria/trillion-wut</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This is not meant to be a political post.]]></summary></entry><entry><title type="html">Relocatable Derivations</title><link href="https://fzakaria.com/2026/06/08/relocatable-derivations" rel="alternate" type="text/html" title="Relocatable Derivations" /><published>2026-06-08T20:39:00-07:00</published><updated>2026-06-08T20:39:00-07:00</updated><id>https://fzakaria.com/2026/06/08/relocatable-derivations</id><content type="html" xml:base="https://fzakaria.com/2026/06/08/relocatable-derivations"><![CDATA[<p>The <a href="/2026/06/05/the-guix-nix-abomination-leveraging-guix-derivations-in-nix">earlier post</a> on <a href="https://github.com/fzakaria/guix-transfer">guix-transfer</a> highlighted how we can use the tool to transfer derivations from <code class="language-plaintext highlighter-rouge">/gnu/store</code> to <code class="language-plaintext highlighter-rouge">/nix/store</code>.</p>

<p>It is always delightful when someone offers deeper insights into an idea I had put forward.</p>

<p>I was so focused on the transfer from derivations from Guix, I failed to see the larger applicability of the tool.</p>

<p><a href="https://github.com/tomberek">@tomberek</a> shared with me the insight that the tool can be generalized to: <em>“transfer derivations between realms”</em>.</p>

<p>Relocatable derivations. 💥</p>

<p>What does that mean?</p>

<p>Perhaps the clearest concept to apply it to are <em>deployments</em>.</p>

<p>You might have a derivation <code class="language-plaintext highlighter-rouge">FooBar.drv</code> that you want to propagate through cascading deployment tiers: alpha, beta, and prod.</p>

<p>You might have needed to painstakingly apply some logical firewall if all three <em>realms</em> used <code class="language-plaintext highlighter-rouge">/nix/store</code> as their prefix to gate your deployment.</p>

<p>By changing the prefix of each one, i.e. <code class="language-plaintext highlighter-rouge">/beta/store</code> or <code class="language-plaintext highlighter-rouge">/prod/store</code>, they are naturally segregated in Nix.</p>

<p>How do we promote derivations from one <em>realm</em> to another?</p>

<p>We could re-evaluate the Nix expression again against each new store or we can leverage <a href="https://github.com/fzakaria/guix-transfer">guix-transfer</a>.</p>

<p>Why is this better than doing <code class="language-plaintext highlighter-rouge">NIX_STORE_DIR=/prod/store nix-instantiate</code> against these new store directories?</p>

<p>What is our source of truth? The Nix files or the derivations?</p>

<p>I <em>posit</em> that the derivations themselves are the source of truth.</p>

<p>Furthermore, evaluation could be slow and requires the full source code (Nix expressions) and the entire evaluation environment (i.e. Nixpkgs, plugins, and overlays).</p>

<p>By relocating at the derivation level, we move from <strong>Evaluation-based deployment</strong> (which is slow, requires source access, and may be prone to evaluation-time impurities potentially) to a <strong>Plan-based deployment</strong>.</p>

<p>We now treat the build graph, via the derivations, as a portable artifact that can be relocated into any realm, regardless of whether that realm has the source code, the right version of Nixpkgs, or in the case of Guix, even speaks the same front-end language.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[The earlier post on guix-transfer highlighted how we can use the tool to transfer derivations from /gnu/store to /nix/store.]]></summary></entry><entry><title type="html">The Guix Nix Abomination: Leveraging Guix derivations in Nix</title><link href="https://fzakaria.com/2026/06/05/the-guix-nix-abomination-leveraging-guix-derivations-in-nix" rel="alternate" type="text/html" title="The Guix Nix Abomination: Leveraging Guix derivations in Nix" /><published>2026-06-05T15:57:00-07:00</published><updated>2026-06-05T15:57:00-07:00</updated><id>https://fzakaria.com/2026/06/05/the-guix-nix-abomination-leveraging-guix-derivations-in-nix</id><content type="html" xml:base="https://fzakaria.com/2026/06/05/the-guix-nix-abomination-leveraging-guix-derivations-in-nix"><![CDATA[<p>Nix and Guix look like rival ecosystems, but under the hood they’re the same “Input  Output Machine”.</p>

<p>Need proof? 🕵 How about we build a Guix derivation with Nix.</p>

<p>First let’s create a super basic derivation in Guix: <em>Hello world</em>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>❯ guix repl <span class="nt">--</span> /dev/stdin <span class="o">&lt;&lt;</span><span class="sh">'</span><span class="no">EOF</span><span class="sh">'
  (use-modules (guix derivations) (guix store))
  (with-store %store
    (let ((drv (derivation %store "simple" "/bin/sh"
                           '("-c" "echo Hello World &gt; </span><span class="nv">$out</span><span class="sh">")
                           #:env-vars '(("PATH" . "/bin"))
                           #:system "x86_64-linux")))
      (format #t "~a</span><span class="se">\n</span><span class="sh">" (derivation-file-name drv))))
</span><span class="no">EOF
</span>/gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv
</code></pre></div></div>

<p>We then ask Nix to build it. 🪄</p>

<p>We ask to use <code class="language-plaintext highlighter-rouge">/gnu/store</code> as the Nix store and have it write its state, database and log files in alternate directories, so it does not collide or mess with Guix.</p>

<blockquote class="alert alert-note">
  <p><strong>Note</strong>
It’s slightly more complicated. Nix happens to check its SQLite database for the derivation, so we need to register it first. The version of Guix (v1.5.0) I’m using leverages a <code class="language-plaintext highlighter-rouge">guix-daemon</code> user that runs inside a private mount namespace where <code class="language-plaintext highlighter-rouge">/gnu/store</code> is writable, but everyone else (including me) sees it as read-only. The <code class="language-plaintext highlighter-rouge">unshare --mount</code> creates a new private mount namespace so I can mount it as read-write and run the Nix command against it.</p>
</blockquote>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
❯ cat &gt; /tmp/register.txt &lt;&lt;'EOF'
/gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv
822a79886102e5ca392cd14358aef0866c36ca526ff1b156f1ded2808a2095df
336

0
EOF

❯ NIX_STORE=/nix/store/fla7gi1dvkw4hvwxar8m7z25p2yv7r40-nix-2.34.7/bin/nix-store

❯ NIX_STORE_DIR=/gnu/store NIX_STATE_DIR=/tmp/nix-gnu/var/nix \
   $NIX_STORE --load-db &lt; /tmp/register.txt

❯ sudo unshare --mount bash -c '
mount -o remount,rw /gnu/store
su -s /bin/bash guix-daemon -c \
    "NIX_STORE_DIR=/gnu/store NIX_STATE_DIR=/tmp/nix-gnu/var/nix \
    NIX_LOG_DIR=/tmp/nix-gnu/var/log/nix \
    /nix/store/fla7gi1dvkw4hvwxar8m7z25p2yv7r40-nix-2.34.7/bin/nix-store \
    --realise /gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv"
'
warning: creating directory "/var/empty/.cache/nix": Permission denied
this derivation will be built:
  /gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv
building '/gnu/store/zr0q11srv4yir8a6wrz582js7zsi17ij-simple.drv'...
warning: you did not specify '--add-root'; the result might be removed by the garbage collector
/gnu/store/kd5szqbl9asz5hravhnxgd9plm4a9gzh-simple

❯ cat /gnu/store/kd5szqbl9asz5hravhnxgd9plm4a9gzh-simple
Hello World
</code></pre></div></div>

<p>We just built a Guix derivation using Nix. 🔥</p>

<p>How is that possible?</p>

<p>Both take a language frontend, Nix or Guile (Scheme), that
compiles to a <strong>derivation</strong> (recipe) and pass that onto a <strong>builder</strong> (daemon) that executes it to produce an output.</p>

<p>What makes them both special is they both promise the same thing: <strong>hermetic builds</strong>. Everything needed to build the output is declared in the recipe: sources, environment variables, dependencies, etc.</p>

<blockquote>
  <p>“Under Nix, a build process will only find resources that have been declared explicitly as dependencies. There’s no way it can build until everything it needs has been correctly declared. If it builds, you will know you’ve provided a complete declaration.” – <a href="https://nixos.org/guides/how-nix-works/">Nix OS Website</a></p>
</blockquote>

<!-- Dot file also in /assets/images/guix-nix-diagram.dot -->
<!-- https://dreampuf.github.io/GraphvizOnline/?engine=dot&compressed=CYSw5gTghgDgFgAjAVxADwPoDt0IN4BQCC0WA1qBALwAyASgNxEIBmA9lgC5ZQC2AplQBEACX4AbAG79OIAMZQhTYljbB%2BCANrsuPAcLFSZ8xQBpWHTgGcQAL0EBGAEwBdZQn7AwG7Zb2DRCWlZBSFzHWs7RwAGN2YsfgB3UjIqTghkfncYKGAqaIA6AFZ3VXUrfhh84vcUiqqHAuimZgB6VoRAAFJOhAA5XAAKTjYYAEou7smp6ZnZufnO5itkACNIWEQ5cWQrTn4IbFxCYmJxKBWJYX60JWZT84kAKx3OYXFbk4RdgE9xQWAoFY4J53MQ5GxxGxqEIAMQAFgAwgB2AAcAEEUR8ThFwZDofDkejMaCLFwbPYqA44SSYPwsIkQMBOHAqE4Wp8cJgzlgwA4tGcLuJhOoWFBkOJOAVOWEvnBYIJVHtzD8-lQWCBxH9gOENeJcVDhDCACIIgCiADYAGIOGX6-GI1EYoRxDnoDDcsBOfkPIVCFhnMj8KXoGVA%2BVURX8ZWcX6CdWazw6zV2w0mi3W20Qg2wh1E50kznuqA8gDM3sFwiBEnEwZuyrltIjbCVXxjqvjWqTeqz%2BLTVpt5hTOcJTridwQheAEEkWnH9wrAB4FysAHwFKeSBetVfLiCtFcLiIIGBsEBcAC05ICAE4hCujfsQNIBpoBkI2MhOGFAGQEoxcpl-LcIhXFdTDnWVwwgfg5E4aNY2EDtEwgD8sHUbUVghYAwnAjshxhDEjSKU0nEzPFDVzJ0wM%2BYhaXpRlmVZccx1dTAAX4XgOFnaiEAFS4l1XTlzzYjisC3HcVj3A8jxPM9OEvKJhFvFcrGLYAMLQBAAGoEBWVBxGAIDLBAqjqLDRt1JLbVW3gxDtRw3U8NNFEnKc0jsxhc1PK8oQmPZE5Cw-TguOo3ihX4ldWk5VpdihfhWm-MSDwk-dD0sY9TwvK9FLvQKYE-QyuGM8CzLjTD9jg9tdUTezkx7Q0ACEUSNOFKIQPCigxNESwRHzPmY-y3Q9PlzxXCc3Q3LQ8IozEXQGrli09BARrG1jp0murh0dGaC0Ghay2Wyc1s0KaR228dDpnA7xqgdjOOOjaPK8zz83O67bqwJbRoCz91rI2EOvRbqXuIABfAg2g6boEAAcVQDSBgwzhhl4cYFjR9H5iWVZ1ngNrtl2fYMBQI5x1C4RYZDElQueXY3ixYgVX%2BQFgWAElHLhIokSKc16dJTh2c57neYiLKqRpOkGSZFk2XBz5ifmnk%2BU0MmhByOQyCgbwrAKKw5F4UMGwVZso2syqEys3CHstI0jVNW23PxU0Oa5nnZuIeWix5L1lZ9StvgJ3gdb1g3w0jCq4yqi2HKtm27dNB3DSdwXXZJD2PTLH2KyEXhixAFh%2BF2IP9frUPjfDtVI67PDrdt%2B3BwepOXZe8cPYmzRwLJ8L12nRLdxS6SMrkrKhCUh8ICffgXzfQKfz-ADRgKzgiu4kqqCgmDy79SvkOQVDEww-TsO4y2-phS1EScBESPr0-G6FkzPloyWGKcXzZZOVubpE4LPk75cV3lkJL%2BHBe7JSkmlGSmUFIjzvCpVC6ktI6T0gZVowFQLFUNlQCyVlGYV3Ng-bE0db7ORIQnWET1npvxbnDDAgUf4nD-quVoYAsDIGisMKC8VQGSVSlwdKsl5IUhgSuXK%2BVUFGXQSvTB7B9LlVNhHfBNVuyn0as1Vq7VOpAyoXLGhQ1PpIBoW3AWTc3YGN2l7fRrcjrGKFqYtOe1LGGOsQ3Z2tjU5OMuqNT%2B71fruQoSnahb1v7LQ9nQ%2B6p8AZdR6rNMGEMJgIAACqkCsGcWQnEoAQGQokHSMhEj8DpCQaCIBaRWAmBjWYzArGeJWhgNu440CMNGmYtA550jFisPnCAxBEqSJOJQLBzY4AENwQfOynxq5FBREUBwmICE4itpM6ZszxxP3otLYoBDwRYF2NAWSaooDiAqHMqEcgJA%2BisGkDI-BmBxDBkAA -->
<p><img src="/assets/images/nix_guix_diagram.svg" alt="Guix Nix Overview" /></p>

<p>Guix, specifically the daemon, was forked from Nix early on, and as a result the two are very similar; they both share the same derivation format, <a href="https://nix.dev/manual/nix/2.25/protocols/derivation-aterm">ATerm</a>, for instance.</p>

<blockquote>
  <p>Guix is based on the Nix package manager – <a href="https://guix.gnu.org/manual/devel/en/guix.html#Acknowledgments">Guix Website</a></p>
</blockquote>

<p>That’s why our earlier example of building the Guix derivation with Nix was possible without much translation.</p>

<p>What if we could leverage an existing recipe from Guix in Nix in its traditional <code class="language-plaintext highlighter-rouge">/nix/store</code>?</p>

<p>If we could convert from one recipe file to the other, we could use the existing recipes from Guix in Nix and vice versa.</p>

<p>Turns out this is far more feasible than you would think, because <em>Guix is
Nix</em> or at least a superset of it.</p>

<p>I, with the help of Claude, built a tool to do just that: <a href="https://github.com/fzakaria/guix-transfer">guix-transfer</a> 🤯.</p>

<blockquote>
  <p><strong>guix-transfer</strong> is a CLI tool for performing bottom-up translation of GNU Guix derivations into Nix.</p>
</blockquote>

<p>Confused? Let us see it in action:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># generate a Guix derivation</span>
❯ guix build hello <span class="nt">--derivations</span>
/gnu/store/2nfg943asrl9dv64zrr1a4kpb25mfafd-hello-2.12.2.drv

<span class="c"># translate it</span>
❯ /guix-transfer /gnu/store/2nfg943asrl9dv64zrr1a4kpb25mfafd-hello-2.12.2.drv
Loading Guix derivation graph from /gnu/store/2nfg943asrl9dv64zrr1a4kpb25mfafd-hello-2.12.2.drv ...
Loaded 228 derivations.
Translating bottom-up ...
<span class="o">[</span>228/228] <span class="k">done
</span>Done. Final Nix derivation:
/nix/store/brdd8zw3j9hhq8zf27ixqyi3l61nwppn-hello-2.12.2.drv
Realise it with: nix-store <span class="nt">--realise</span> <span class="nt">--option</span> filter-syscalls <span class="nb">false</span> /nix/store/brdd8zw3j9hhq8zf27ixqyi3l61nwppn-hello-2.12.2.drv

<span class="c"># build it with Nix</span>
<span class="c"># this is a LONG multi-hour build since we build everything from source</span>
❯ nix-store <span class="nt">--option</span> filter-syscalls <span class="nb">false</span> <span class="nt">--realise</span> <span class="se">\</span>
/nix/store/brdd8zw3j9hhq8zf27ixqyi3l61nwppn-hello-2.12.2.drv

❯ /nix/store/j3940mdzr6qmw4ydhyla663s501vb8ns-hello-2.12.2/bin/hello
Hello, world!
</code></pre></div></div>

<blockquote class="alert alert-note">
  <p><strong>Note</strong>
When you unpack a tarball, tar restores each file’s original permissions, including setuid/setgid bits. Nix’s sandbox installs a seccomp filter that blocks any <code class="language-plaintext highlighter-rouge">chmod</code> call that sets these bits, returning “Operation not permitted”. Guix’s early bootstrap uses a Scheme-based <code class="language-plaintext highlighter-rouge">tar</code> (gash-utils) that treats this error as fatal, unlike GNU tar which silently skips it. The fix is <code class="language-plaintext highlighter-rouge">--option filter-syscalls false</code>, which disables the filter.</p>
</blockquote>

<p>If it’s not clear what we just did: we took a Guix derivation and all of its dependencies (down to the bootstrap seeds), translated it to a Nix derivation, and built it with Nix. 😲</p>

<p>What is this <u>abomination</u> and how was this possible!?</p>

<p>It’s important to revisit what a derivation is, and how it’s used in Nix and Guix to better understand how this is possible. Let’s look at the same basic derivation from earlier, <em>Hello World</em>.</p>

<blockquote>
  <p>You might want to check out my other post on <a href="/2025/03/23/nix-derivations-by-hand">Nix derivations by hand</a> if this interests you 🤓.</p>
</blockquote>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">derivation</span> <span class="p">{</span>
  <span class="nv">name</span> <span class="o">=</span> <span class="s2">"simple"</span><span class="p">;</span>
  <span class="nv">builder</span> <span class="o">=</span> <span class="s2">"/bin/sh"</span><span class="p">;</span>
  <span class="nv">system</span> <span class="o">=</span> <span class="kr">builtins</span><span class="o">.</span><span class="nv">currentSystem</span><span class="p">;</span>
  <span class="nv">args</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"-c"</span> <span class="s2">''</span><span class="err">
</span><span class="s2">    echo "Hello World" &gt; $out</span><span class="err">
</span><span class="s2">  ''</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p>When we evaluate (nix-instantiate) this derivation, we get a path to a file that contains the derivation in the <a href="https://nix.dev/manual/nix/2.25/protocols/derivation-aterm">ATerm</a> format:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>❯ nix-instantiate - &lt;&lt; 'EOF'
derivation {
  name = "simple";
  builder = "/bin/sh";
  system = builtins.currentSystem;
  args = ["-c" ''
    echo "Hello World" &gt; $out
  ''];
}
EOF
/nix/store/w4mcfbibhjgri1nm627gb9whxxd65gmi-simple.drv
</code></pre></div></div>

<p>If we look at the contents of the file, we can see the ATerm representation of the derivation:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Derive(
  [("out", "/nix/store/r4c710xzfqrqw2wd6cinxwgmh44l4cy2-simple", "", "")],
  [],
  [],
  "x86_64-linux",
  "/bin/sh",
  ["-c", "echo \"Hello World\" &gt; $out\n"],
  [
    ("builder", "/bin/sh"),
    ("name", "simple"),
    ("out", "/nix/store/r4c710xzfqrqw2wd6cinxwgmh44l4cy2-simple"),
    ("system", "x86_64-linux")
  ]
)
</code></pre></div></div>

<p>This <strong>has all the information</strong> we need to build the output by the builder. At this point, it’s really not Nix specific anymore. The same applies for the Guix derivations.</p>

<p>The derivations do not “know” whether they came from Scheme or Nix. It’s a recipe. The insight then is if we rewrite the store paths from <code class="language-plaintext highlighter-rouge">/gnu/store</code> to <code class="language-plaintext highlighter-rouge">/nix/store</code>, and swap some builtins (i.e. <code class="language-plaintext highlighter-rouge">builtin:download</code> for <code class="language-plaintext highlighter-rouge">builtin:fetchurl</code>), we can get <code class="language-plaintext highlighter-rouge">nix-daemon</code> to build it <em>identically</em>. 💡</p>

<p>The only difference in more complex derivations is that they have dependencies, which are also derivations, and the builder references them so it forms a graph of derivations, each built by the builder in topological order.</p>

<p>The leaves of this tree for any non-trivial derivation are the bootstrap seeds: <code class="language-plaintext highlighter-rouge">gcc</code>, <code class="language-plaintext highlighter-rouge">awk</code>, <code class="language-plaintext highlighter-rouge">bash</code>, <code class="language-plaintext highlighter-rouge">tar</code> etc. Guix is famous for bootstrapping itself from <strong>a 357-byte binary as source</strong> [<a href="https://guix.gnu.org/manual/1.5.0/en/html_node/Full_002dSource-Bootstrap.html">ref</a>]. Since at no point do the bootstrap seeds depend on <code class="language-plaintext highlighter-rouge">/gnu/store</code> being the prefix, the translated chain builds identically under Nix.</p>

<p><code class="language-plaintext highlighter-rouge">guix-transfer</code> walks a Guix <code class="language-plaintext highlighter-rouge">.drv</code> graph in post-order and for each
derivation:</p>

<ol>
  <li>
    <p>Guix’s <code class="language-plaintext highlighter-rouge">builtin:download</code> is replaced with
Nix’s <code class="language-plaintext highlighter-rouge">builtin:fetchurl</code>. Same idea, different name.</p>
  </li>
  <li>
    <p>Source files are added to the Nix store, with embedded
<code class="language-plaintext highlighter-rouge">/gnu/store</code> paths rewritten to their <code class="language-plaintext highlighter-rouge">/nix/store</code> equivalents.</p>
  </li>
  <li>
    <p>Every <code class="language-plaintext highlighter-rouge">/gnu/store</code> reference: input drvs, builder path, args,
env vars are rewritten to the mapped <code class="language-plaintext highlighter-rouge">/nix/store</code> path.</p>
  </li>
  <li>
    <p>Output paths are blanked as Nix recomputes them via
<a href="https://fzakaria.com/2025/10/29/nix-derivation-madness"><code class="language-plaintext highlighter-rouge">hashDerivationModulo</code></a>.</p>
  </li>
  <li>
    <p>The result is serialised as JSON and registered with
<code class="language-plaintext highlighter-rouge">nix derivation add</code>.</p>
  </li>
</ol>

<p>That’s it. No Nix expressions are generated. No <code class="language-plaintext highlighter-rouge">stdenv</code>. No mapping
of Guix packages to nixpkgs equivalents. The Guix derivation graph is
translated <em>faithfully</em>, and <code class="language-plaintext highlighter-rouge">nix-daemon</code> builds it.</p>

<blockquote class="alert alert-note">
  <p><strong>Note</strong>
Interestingly, <code class="language-plaintext highlighter-rouge">builtin:fetchurl</code> takes exactly one URL and cannot
fall back. Guix derivations carry lists of mirrors, many of which are
flaky or dead. Similar to Nix, Guix operates a content-addressed mirror
at <code class="language-plaintext highlighter-rouge">bordeaux.guix.gnu.org</code> that serves <em>any</em> source its CI has ever seen.
We leverage this for the <code class="language-plaintext highlighter-rouge">fetchurl</code> instead of the original source URL.</p>
</blockquote>

<p>Now that we have a way to <em>slurp</em> Guix packages into Nix, we can start to do some diabolical combinations by combining <em>native</em> Nix and Guix packages together!</p>

<p>We can take our <code class="language-plaintext highlighter-rouge">hello</code> package we built in Nix and leverage it in a Nix derivation.</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span>
<span class="nv">guixHello</span> <span class="o">=</span> <span class="sx">/nix/store/...-hello-2.12.2</span><span class="p">;</span>
<span class="kn">in</span>
<span class="kr">derivation</span> <span class="p">{</span>
  <span class="nv">name</span> <span class="o">=</span> <span class="s2">"nix-hello-world"</span><span class="p">;</span>
  <span class="nv">system</span> <span class="o">=</span> <span class="s2">"x86_64-linux"</span><span class="p">;</span>
  <span class="nv">builder</span> <span class="o">=</span> <span class="s2">"/bin/sh"</span><span class="p">;</span>
  <span class="nv">args</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">"-c"</span> <span class="s2">"echo </span><span class="se">\"</span><span class="s2">$(</span><span class="si">${</span><span class="nv">guixHello</span><span class="si">}</span><span class="s2">/bin/hello) from Nix</span><span class="se">\"</span><span class="s2"> &gt; $out"</span> <span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Nix automatically scans your derivations for anything prefixed with <code class="language-plaintext highlighter-rouge">/nix/store</code> and tracks it as an input dependency. This is similar to how store paths are interpolated when you do something like <code class="language-plaintext highlighter-rouge">${pkgs.hello}/bin/hello</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>❯ nix-build <span class="nt">--no-out-link</span> hello-from-nix.nix

❯ <span class="nb">cat</span> /nix/store/...-run-guix-hello
Hello, world! from Nix
</code></pre></div></div>

<p>If writing the <code class="language-plaintext highlighter-rouge">/nix/store</code> paths raw in the Nix expression is a little <em>too raw</em> for you, we can build something more ergonic pretty easily as well.
<code class="language-plaintext highlighter-rouge">guix-transfer</code> has an <code class="language-plaintext highlighter-rouge">--emit-nix</code> mode that instead will emit the Nix expression for the translated <code class="language-plaintext highlighter-rouge">.drv</code>.</p>

<p>Let’s look at a slightly more complex example that uses Guix’s <code class="language-plaintext highlighter-rouge">guile</code> to build a derivation with dependencies:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>❯ guix repl <span class="nt">--</span> /dev/stdin <span class="o">&lt;&lt;</span><span class="sh">'</span><span class="no">EOF</span><span class="sh">'
  (use-modules (guix derivations) (guix store) (guix packages)
               (gnu packages bootstrap))
  (with-store store
    (let* ((guile-drv (package-derivation store %bootstrap-guile))
           (guile-out (derivation-&gt;output-path guile-drv))
           (drv (derivation store "demo" (string-append guile-out "/bin/guile")
                            `("--no-auto-compile" "-c"
                              ,(string-append
                                 "(call-with-output-file (getenv </span><span class="se">\"</span><span class="sh">out</span><span class="se">\"</span><span class="sh">) "
                                 "  (lambda (p) (display </span><span class="se">\"</span><span class="sh">Hello from Guix!</span><span class="se">\\</span><span class="sh">n</span><span class="se">\"</span><span class="sh"> p)))"))
                            #:inputs (list (derivation-input guile-drv))
                            #:system "x86_64-linux")))
      (format #t "~a</span><span class="se">\n</span><span class="sh">" (derivation-file-name drv))))
</span><span class="no">EOF

</span>❯ guix build /gnu/store/fln2d17fyqka3gafcdqyhfyl1nzml5jn-demo.drv
successfully built /gnu/store/fln2d17fyqka3gafcdqyhfyl1nzml5jn-demo.drv
/gnu/store/l66zvywi60ljhk3kwwaay156cgsc2ahg-demo

❯ <span class="nb">cat</span> /gnu/store/l66zvywi60ljhk3kwwaay156cgsc2ahg-demo
Hello from Guix!
</code></pre></div></div>

<p>We can now convert this to a Nix expression with <code class="language-plaintext highlighter-rouge">guix-transfer</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>❯ guix-transfer /gnu/store/fln2d17fyqka3gafcdqyhfyl1nzml5jn-demo.drv <span class="nt">--emit-nix</span> /tmp/demo.nix
...
Realise it with: nix-store <span class="nt">--realise</span> <span class="nt">--option</span> filter-syscalls <span class="nb">false</span> /nix/store/fkj4vz6vs85s2x3dwhg5ysfwyr8rv4a5-demo.drv
Emitted Nix expression: /tmp/demo.nix
</code></pre></div></div>

<p>We realise the derivation with <code class="language-plaintext highlighter-rouge">nix-store --realise</code> or we can <code class="language-plaintext highlighter-rouge">nix-build</code> the Nix expression. Please notice that both <strong>produce the exact same hash</strong>: <code class="language-plaintext highlighter-rouge">/nix/store/rq5bc9crsg1hrr7afllzjgi7z8bl21zy-demo</code>.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>❯ nix-build /tmp/demo.nix
/nix/store/rq5bc9crsg1hrr7afllzjgi7z8bl21zy-demo

❯ nix-store <span class="nt">--realise</span> <span class="nt">--option</span> filter-syscalls <span class="nb">false</span> /nix/store/zgwdbfpigl8cwy5d85p0rdcl21x3bszm-demo.drv
/nix/store/rq5bc9crsg1hrr7afllzjgi7z8bl21zy-demo

❯ <span class="nb">cat</span> /nix/store/rq5bc9crsg1hrr7afllzjgi7z8bl21zy-demo
Hello from Guix!
</code></pre></div></div>

<p>We can now use this Guix derivation like any normal Nix expression, such as the ones you might encounter in Nixpkgs.</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span>
  <span class="nv">guixDemo</span> <span class="o">=</span> <span class="kr">import</span> <span class="sx">/tmp/demo.nix</span><span class="p">;</span>
<span class="kn">in</span>
<span class="kr">derivation</span> <span class="p">{</span>
  <span class="nv">name</span> <span class="o">=</span> <span class="s2">"use-guix-demo"</span><span class="p">;</span>
  <span class="nv">system</span> <span class="o">=</span> <span class="s2">"x86_64-linux"</span><span class="p">;</span>
  <span class="nv">builder</span> <span class="o">=</span> <span class="s2">"/bin/sh"</span><span class="p">;</span>
  <span class="nv">args</span> <span class="o">=</span> <span class="p">[</span> <span class="s2">"-c"</span> <span class="s2">"echo </span><span class="se">\"</span><span class="s2">Nix says: $(cat </span><span class="si">${</span><span class="nv">guixDemo</span><span class="si">}</span><span class="s2">)</span><span class="se">\"</span><span class="s2"> &gt; $out"</span> <span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p>That means we could even build a <code class="language-plaintext highlighter-rouge">flake</code> that is all of Guix packages available for use.</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
  <span class="nv">outputs</span> <span class="o">=</span> <span class="p">{</span> <span class="nv">self</span> <span class="p">}:</span> <span class="p">{</span>
    <span class="nv">packages</span><span class="o">.</span><span class="nv">x86_64-linux</span><span class="o">.</span><span class="nv">demo</span> <span class="o">=</span> <span class="kr">import</span> <span class="sx">./demo.nix</span><span class="p">;</span>
  <span class="p">};</span>
<span class="p">}</span>
</code></pre></div></div>

<p>My mind is blown. 🤯</p>

<p><a href="https://github.com/nixos/nixpkgs">Nixpkgs</a> is known as the world’s largest package repository, and now we have made a way for it suddenly to become even larger by borrowing <strong>any</strong> derivation from Guix!</p>

<p>The real <em>power</em> behind Nix are the derivations and that they are hermetic, declaring any dependency needed. We’ve seen that we can transfer these recipes to any <em>store-based</em> system that has similar qualities and preserve the reproducibility.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Nix and Guix look like rival ecosystems, but under the hood they’re the same “Input Output Machine”.]]></summary></entry><entry><title type="html">Every byte matters</title><link href="https://fzakaria.com/2026/06/01/every-byte-matters" rel="alternate" type="text/html" title="Every byte matters" /><published>2026-06-01T13:07:00-07:00</published><updated>2026-06-01T13:07:00-07:00</updated><id>https://fzakaria.com/2026/06/01/every-byte-matters</id><content type="html" xml:base="https://fzakaria.com/2026/06/01/every-byte-matters"><![CDATA[<p>I have spent a large portion of my career working in Java. In that time, you get used to huge classes. New functionality? Just add a new method and field to the class.
The cost of each new field is rarely considered. Performance is often considered from a <em>classic computer science</em> perspective by considering asymptotic analysis of the algorithms and data structures in-use.</p>

<p>Turns out that even within a growth scale for your algorithm, such as a simple for-loop <code class="language-plaintext highlighter-rouge">O(N)</code>, time can vary dramatically if we have a little deeper understanding of the underlying hardware.</p>

<p>First, let’s understand our current machine. Let’s take a peek at our <em>cache line</em> and <em>page</em> sizes.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>lscpu | <span class="nb">grep</span> <span class="nt">-i</span> cache
  L1d cache:    352 KiB <span class="o">(</span>10 instances<span class="o">)</span>
  L1i cache:    640 KiB <span class="o">(</span>10 instances<span class="o">)</span>
  L2 cache:     10 MiB <span class="o">(</span>5 instances<span class="o">)</span>
  L3 cache:     12 MiB <span class="o">(</span>1 instance<span class="o">)</span>

<span class="nv">$ </span>getconf LEVEL1_DCACHE_LINESIZE
  64
</code></pre></div></div>

<p>The <em>instances</em> number is a reflection of how the caches are shared amongst CPUs. If I had 10 CPUs, each one has their own <code class="language-plaintext highlighter-rouge">L1d</code> cache, whereas two of them would share an <code class="language-plaintext highlighter-rouge">L2</code> cache.</p>

<p>Our cache line size is <strong>64 bytes</strong>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌─────────────────────────────────────────────┐
│                 64 bytes                    │
│  byte 0   byte 1   byte 2   ...  byte 63    │
└─────────────────────────────────────────────┘
</code></pre></div></div>

<p>When you read <strong>a single</strong> byte from memory, the hardware will fill the surrounding 64 bytes into the cache line.
The idea being that data is often temporal and spatially located, meaning data is often accessed near each other and close in time to each other.</p>

<p>We can reference Jeff Dean’s famous <a href="https://colin-scott.github.io/personal_website/research/interactive_latency.html">“Latency numbers every programmer should know”</a>, however a quick recap with the values from our particular machine is the following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌──────────────────────────────────────────────────────────────┐
│                           CPU Core                           │
│  ┌───────────┐                                               │
│  │ Registers │  &lt; 1 ns                                       │
│  └─────┬─────┘                                               │
│        ▼                                                     │
│  ┌───────────┐                                               │
│  │ L1d Cache │  ~35 KiB/core    ~4-5 cycles    ~1-2 ns       │
│  │           │  ~560 cache lines                             │
│  └─────┬─────┘                                               │
│        ▼                                                     │
│  ┌───────────┐                                               │
│  │ L2 Cache  │  ~2 MiB/core-pair  ~12-15 cycles  ~4-5 ns     │
│  │           │  ~32,000 cache lines                          │
│  └─────┬─────┘                                               │
│        ▼                                                     │
│  ┌───────────┐                                               │
│  │ L3 Cache  │  12 MiB shared   ~30-40 cycles   ~10-15 ns    │
│  │           │  ~196,000 cache lines                         │
│  └─────┬─────┘                                               │
│        ▼                                                     │
│  ┌───────────┐                                               │
│  │   DRAM    │  ~100-200 cycles  ~60-100 ns                  │
│  │           │                                               │
│  └───────────┘                                               │
└──────────────────────────────────────────────────────────────┘
</code></pre></div></div>

<p>The sizes for each cache, is the number returned by <code class="language-plaintext highlighter-rouge">lscpu</code> divided by the number of cores or instances; i.e. 352 KiB ÷ 10 instances = ~35 KiB.
We then determine the number of cache lines by dividing this number by 64; i.e. 35 KiB ÷ 64 bytes = 560 cache lines.</p>

<p>How does this all matter ? 🤔</p>

<p>Let’s consider an example where we want to iterate over a single struct <code class="language-plaintext highlighter-rouge">Monster</code> and pull out the <code class="language-plaintext highlighter-rouge">boolean is_alive</code> to filter them.
We create our struct, and in this particular example we need 64 bytes to represent a single Monster.</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">Monster</span> <span class="p">{</span>
      <span class="kt">uint32_t</span> <span class="n">id</span><span class="p">;</span>          <span class="c1">// 4 bytes</span>
      <span class="kt">float</span>    <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">;</span>     <span class="c1">// 12 bytes</span>
      <span class="kt">float</span>    <span class="n">vx</span><span class="p">,</span> <span class="n">vy</span><span class="p">,</span> <span class="n">vz</span><span class="p">;</span>  <span class="c1">// 12 bytes</span>
      <span class="kt">int32_t</span>  <span class="n">hp</span><span class="p">;</span>          <span class="c1">// 4 bytes</span>
      <span class="kt">int32_t</span>  <span class="n">attack</span><span class="p">;</span>      <span class="c1">// 4 bytes</span>
      <span class="kt">int32_t</span>  <span class="n">defense</span><span class="p">;</span>     <span class="c1">// 4 bytes</span>
      <span class="kt">uint8_t</span>  <span class="n">is_alive</span><span class="p">;</span>    <span class="c1">// 1 byte</span>
      <span class="kt">uint8_t</span>  <span class="n">team</span><span class="p">;</span>        <span class="c1">// 1 byte</span>
      <span class="kt">char</span>     <span class="n">name</span><span class="p">[</span><span class="mi">22</span><span class="p">];</span>    <span class="c1">// 22 bytes</span>
  <span class="p">};</span>                        <span class="c1">// total: 64 bytes</span>
</code></pre></div></div>

<p>If we had an array of Monsters and we iterate over them, the cache line would fill up like so.
Each cache line would fill with a single monster, and we would fetch only the <code class="language-plaintext highlighter-rouge">is_alive</code> byte.</p>

<p>This is often referred to as “Array of Structs”.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>       cache line 0                          cache line 1
┌──────────────────────────────┐   ┌──────────────────────────────┐
│ id0 x0 y0 z0 vx0 vy0 vz0 hp0 │   │ id1 x1 y1 z1 vx1 vy1 vz1 hp1 │
│ atk0 def0 alive0 team0 name0 │   │ atk1 def1 alive1 team1 name1 │
│             ▲                │   │            ▲                 │
└─────────────┼────────────────┘   └────────────┼─────────────────┘
              │                                 │
          need this                          need this
</code></pre></div></div>

<p>If we instead normalize the data such that each field is in it’s own list, we can pack the cache lines much tighter.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>                        cache line 0
┌───────────────────────────────────────────────────────────────┐
│alive0 alive1 alive2 alive3 alive4 alive5 ... alive62 alive63  │
│  ▲      ▲      ▲      ▲      ▲      ▲          ▲       ▲      │
└──┼──────┼──────┼──────┼──────┼──────┼──────────┼───────┼──────┘
   │      │      │      │      │      │          │       │
   └──────┴──────┴──────┴──────┴──────┴──────────┴───────┘
                  all 64 in one fetch
</code></pre></div></div>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// SoA layout</span>
<span class="k">struct</span> <span class="nc">Monsters</span> <span class="p">{</span>
    <span class="kt">uint32_t</span> <span class="o">*</span><span class="n">ids</span><span class="p">;</span>
    <span class="kt">float</span>    <span class="o">*</span><span class="n">xs</span><span class="p">,</span> <span class="o">*</span><span class="n">ys</span><span class="p">,</span> <span class="o">*</span><span class="n">zs</span><span class="p">;</span>
    <span class="kt">float</span>    <span class="o">*</span><span class="n">vxs</span><span class="p">,</span> <span class="o">*</span><span class="n">vys</span><span class="p">,</span> <span class="o">*</span><span class="n">vzs</span><span class="p">;</span>
    <span class="kt">int32_t</span>  <span class="o">*</span><span class="n">hps</span><span class="p">;</span>
    <span class="kt">int32_t</span>  <span class="o">*</span><span class="n">attacks</span><span class="p">;</span>
    <span class="kt">int32_t</span>  <span class="o">*</span><span class="n">defenses</span><span class="p">;</span>
    <span class="kt">uint8_t</span>  <span class="o">*</span><span class="n">is_alives</span><span class="p">;</span>    <span class="c1">// packed contiguously</span>
    <span class="kt">uint8_t</span>  <span class="o">*</span><span class="n">teams</span><span class="p">;</span>
    <span class="kt">char</span>     <span class="p">(</span><span class="o">*</span><span class="n">names</span><span class="p">)[</span><span class="mi">22</span><span class="p">];</span>
<span class="p">};</span>
</code></pre></div></div>

<p>This type of layout is referred to as “Struct of Arrays”.</p>

<p>How much of an impact can this have?</p>

<p><a href="/assets/images/aos_vs_soa.png"><img src="/assets/images/aos_vs_soa_50p.png" alt="graph of soa" /></a></p>

<p>We can observe up to <strong>30x</strong> improvements when the Monster struct is 1KiB 🤯</p>

<p>The delta is less observable when the struct is small because multiple Monster structs can still be fetched within a single cache-line.</p>

<p>This data access is incredibly hot though. Your CPU pre-fetcher knows it’s going sequentially and fetches the next cache line before you need it. You never actually have to wait for the memory to be fetched.</p>

<p>What about random access patterns?</p>

<p>Not all access patterns are sequential. Hash maps, trees, graph traversal, and pointer-heavy data structures jump to unpredictable locations. The CPU can’t prefetch what it can’t predict. With random access, the CPU needs the entire array to be present in the cache in order to avoid stalls due to memory lookup.</p>

<p>This means the <strong>total size of your collection</strong> determines your performance tier.</p>

<table>
  <thead>
    <tr>
      <th>Monsters</th>
      <th>Working Set (64B)</th>
      <th>Latency (64B)</th>
      <th>Working Set (128B)</th>
      <th>Latency (128B)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>512</td>
      <td>32 KiB</td>
      <td>~3 ns</td>
      <td>64 KiB</td>
      <td>~11 ns</td>
    </tr>
    <tr>
      <td>4,096</td>
      <td>256 KiB</td>
      <td>~11 ns</td>
      <td>512 KiB</td>
      <td>~13 ns</td>
    </tr>
    <tr>
      <td>32,768</td>
      <td>2 MiB</td>
      <td>~29 ns</td>
      <td>4 MiB</td>
      <td>~43 ns</td>
    </tr>
    <tr>
      <td>65,536</td>
      <td>4 MiB</td>
      <td>~49 ns</td>
      <td>8 MiB</td>
      <td>~65 ns</td>
    </tr>
    <tr>
      <td>131,072</td>
      <td>8 MiB</td>
      <td>~163 ns</td>
      <td>16 MiB</td>
      <td>~162 ns</td>
    </tr>
  </tbody>
</table>

<p>Doubling the struct from 64B to 128B doubles the working set for the same number of monsters, pushing the data into slower cache levels. At just 512 monsters, a 64B struct fits in L1d at ~3 ns — but a 128B struct has already spilled to L2 at ~11 ns.</p>

<p>We can observe this with a pointer-chasing benchmark. We allocate N monster-sized nodes, wire them into a random order, and chase pointers. Each hop lands at an unpredictable address,
defeating the CPU’s prefetcher entirely.</p>

<p><a href="/assets/images/cache_staircase.png"><img src="/assets/images/cache_staircase_50p.png" alt="graph of soa" /></a></p>

<p>Rather than graph it logarithmically, which I find sometimes is easy to miss, I have included a zoomed in graph. We can see that all struct sizes hit the same <em>staircase</em> like pattern as they go through the various cache levels however the larger struct sizes are <em>shifted left</em>, meaning they hit the increase earlier.</p>

<p>This means for random access patterns, if you can keep tight control on your total working set size, you can drastically affect the time.</p>

<p>Knowing your struct and working set size can make a substantial difference.</p>

<blockquote class="alert alert-note">
  <p><strong>Update (08/07/2026)</strong>
If you interested in exploring this further or trying to create the numbers yourself, I have uploaded the benchmarks to GitHub <a href="https://gist.github.com/fzakaria/93183b2f3f3038ebb9e4f9fdbf377195">here</a>.</p>
</blockquote>]]></content><author><name></name></author><summary type="html"><![CDATA[I have spent a large portion of my career working in Java. In that time, you get used to huge classes. New functionality? Just add a new method and field to the class. The cost of each new field is rarely considered. Performance is often considered from a classic computer science perspective by considering asymptotic analysis of the algorithms and data structures in-use.]]></summary></entry></feed>