<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/default.xsl"?>
<fr:tree xmlns:fr="http://www.forester-notes.org" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:xml="http://www.w3.org/XML/1998/namespace" root="false" base-url="/">
  <fr:frontmatter>
    <fr:authors />
    <fr:uri>https://patrick.sirref.org/shelter/</fr:uri>
    <fr:display-uri>shelter</fr:display-uri>
    <fr:route>/shelter/</fr:route>
    <fr:title text="Shelter">Shelter</fr:title>
    <fr:meta name="external">https://tangled.sh/@patrick.sirref.org/shelter</fr:meta>
  </fr:frontmatter>
  <fr:mainmatter>
    <html:p>A shim between a user and the shell that provides greater reproducibility and insight into what your code is doing!</html:p>
    <fr:tree show-metadata="false" numbered="false">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Give me Shelter!">Give me Shelter!</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <html:p>Shelter combines the caching and reproducibility of Dockerfiles with the ease of interaction of the shell. I'd be interested to use <fr:link href="/ryangibb/" title="Ryan Gibb" uri="https://patrick.sirref.org/ryangibb/" display-uri="ryangibb" type="local">Ryan</fr:link>'s <fr:link href="https://ryan.freumh.org/research.html" type="external">package management work</fr:link> as a means to specify the base environment users want.</html:p>
        <html:p>Here is an example of running Shelter and making use of the branchable sessions.</html:p>
        <html:pre class="ansi2html-content"><html:span class="ansi33">shelter&gt; </html:span>echo hello &gt; hello.txt
<html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">main</html:span>#<html:span class="ansi35">bbd691a</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }> @ session exp-1]]><html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">bbd691a</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }> echo world >> hello.txt]]><html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">dd5bab8</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }> @ session main]]><html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">main</html:span>#<html:span class="ansi35">bbd691a</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }> echo "to the" >> hello.txt]]><html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">main</html:span>#<html:span class="ansi35">b9abef4</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }> cat hello.txt
hello
to the]]><html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">main</html:span>#<html:span class="ansi35">d1c1728</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }> @ session exp-1]]><html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">dd5bab8</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }> @ replay main]]><html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">df1b4e1</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }> cat hello.txt
hello
to the
world]]><html:span class="ansi33">shelter</html:span><![CDATA[[]]><html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">67162b7</html:span><![CDATA[] : { mode:]]><html:span class="ansi31">rw</html:span><![CDATA[ }>]]></html:pre>
        <html:p>The <html:code>@</html:code> character allows the user to interact directly with Shelter's build-in operators. <html:code>@ session exp-1</html:code> creates a new session as there is no <html:code>exp-1</html:code> session. It points to the head commit of the branch it came from (<html:code>git checkout -b exp-1</html:code>).</html:p>
        <html:p>From there we make changes and switch between branches until we perform a replay. A replay is a rebase without any merge conflict checks, it simply finds the <html:em>least common ancestor</html:em> of the two branches and re-applies the commits from your current branch (here <html:code>exp-1</html:code>) onto the head of the target branch (here <html:code>main</html:code>).</html:p>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" numbered="false">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Under the hood">Under the hood</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <html:p>Shelter is a light-weight, reimplementation of <fr:link href="https://github.com/ocurrent/obuilder" type="external">obuilder</fr:link>. It uses the similar ideas, like snapshotting filesystems (e.g. <fr:link href="https://github.com/patricoferris/ocaml-zfs" type="external">ZFS</fr:link>) and Linux namespaces (e.g. <fr:link href="https://github.com/quantifyearth/void" type="external">Void</fr:link>). Between the low-level store and the interactive shell parts, there is an <fr:link href="https://github.com/mirage/irmin" type="external">Irmin</fr:link> store.</html:p>
      </fr:mainmatter>
    </fr:tree>
  </fr:mainmatter>
  <fr:backmatter>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="References">References</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Context">Context</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Backlinks">Backlinks</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2026</fr:year>
              <fr:month>6</fr:month>
              <fr:day>17</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/a-shell-is-born/</fr:uri>
            <fr:display-uri>a-shell-is-born</fr:display-uri>
            <fr:route>/a-shell-is-born/</fr:route>
            <fr:title text="A Shell is Born">A Shell is Born</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> passed a milestone this week after installing the following packages <html:code>vim fakeroot fakechroot debootstrap</html:code> and successfully performing a <fr:link href="https://wiki.debian.org/fakechroot" type="external">fakechroot debootstrap</fr:link>.</html:p>
            <html:p>To me, this signals that <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is closer than ever to being an <html:em>actual</html:em> POSIX-ish shell. This is exciting because we now have a completely customisable, OCaml implementation of a shell that can run a significant number of existing shell scripts in the world. Let the hacking commence!</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>17</fr:day>
                </fr:date>
                <fr:title text="Installation">Installation</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>You can install the binary, <html:code>msh</html:code>, today:</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="sh-source">opam pin git+https://git.sirref.org/merry
</html:span>
                    <html:span class="sh-support-function-builtin">eval</html:span>
                    <html:span class="sh-source"> </html:span>
                    <html:span class="sh-punctuation-definition-string-begin"><![CDATA[$(]]></html:span>
                    <html:span class="sh-string-interpolated-dollar">opam env</html:span>
                    <html:span class="sh-punctuation-definition-string-end"><![CDATA[)]]></html:span>
                    <html:span class="sh-source">
</html:span>
                    <html:span class="sh-source">msh
</html:span>
                  </html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>17</fr:day>
                </fr:date>
                <fr:title text="What's next?">What's next?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>There are a few avenues to try next. In the short-term, more testing of the shell is probably worthwhile. In particular, trying to boot an Alpine Linux image with <html:code>msh</html:code> as the default shell would be good.</html:p>
                <html:p>Integrating the various components of <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> is also on the list. A time-travelling POSIX shell is within reach; the actual semantics still need to be ironed out.</html:p>
                <html:p>I know for certain that some shell options and built-ins will be the first issues to arise going forward.</html:p>
                <html:p>As a fun experiment, <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link>'s vibecoded <fr:link href="https://tangled.org/anil.recoil.org/ocaml-bbox" type="external">OCaml busybox translation</fr:link> could be plumbed into <html:code>msh</html:code>. This would allow a very versatile, but <html:em>zero-forking</html:em> shell! Throw in an in-memory Eio filesystem into the mix and the whole thing becomes in-memory... <fr:link href="https://mirage.io/" type="external"><html:code>mirageSH</html:code></fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>17</fr:day>
                </fr:date>
                <fr:title text="Weeknotes">Weeknotes</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Below are a collection of weeknotes for <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>.</html:p>
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>4</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/weekly-2026-w26/</fr:uri>
                    <fr:display-uri>weekly-2026-w26</fr:display-uri>
                    <fr:route>/weekly-2026-w26/</fr:route>
                    <fr:title text="Shell Benchmarks, Back to Writing">Shell Benchmarks, Back to Writing</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>A little late due to travel, but I did a little benchmarking of <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>4</fr:day>
                        </fr:date>
                        <fr:title text="Signal Handling in Merry">Signal Handling in Merry</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>In order to even run <fr:link href="https://github.com/shellspec/shellbench" type="external">shellbench</fr:link>, I first had to fix some bugs in the shell implementation. Shellbench aims to warm up the shell before starting any benchmarks; it includes this prelude before getting started:</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="sh-source">__ready=
</html:span>
                            <html:span class="sh-support-function-builtin">trap</html:span>
                            <html:span class="sh-source"> __ready=1 HUP
</html:span>
                            <html:span class="sh-support-function-builtin">kill</html:span>
                            <html:span class="sh-source"> -HUP </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">MAIN_PID</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-source">
</html:span>
                            <html:span class="sh-keyword-control">until</html:span>
                            <html:span class="sh-meta-scope-while-loop"><![CDATA[ []]></html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">__ready</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-meta-scope-while-loop"><![CDATA[ ]]]></html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-while-loop"> </html:span>
                            <html:span class="sh-keyword-control">do</html:span>
                            <html:span class="sh-meta-scope-while-loop"> __dummy=</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-while-loop"> </html:span>
                            <html:span class="sh-keyword-control">done</html:span>
                            <html:span class="sh-source">
</html:span>
                          </html:code>
                        </html:pre>
                        <html:p>Whilst writing <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>, I hadn't really considered that the return context from a trap needed to be taken into consideration! I had assumed they would be silently ignored, how else would we know where to thread that context back into the shell's execution.</html:p>
                        <html:p>Even after reading through the specification for <fr:link href="https://pubs.opengroup.org/onlinepubs/009604599/utilities/trap.html" type="external">trap</fr:link> I am still none the wiser. I've opted to place some sensible signal polling points during the execution of the commands to run any signals that have come in. The single handlers in <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> simply push thunks onto a run queue. Looking at the Dash source code, it <fr:link href="https://git.kernel.org/pub/scm/utils/dash/dash.git/tree/src/eval.c#n230" type="external">seems to be something that happens just before evaluation</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>4</fr:day>
                        </fr:date>
                        <fr:title text="Benchmarking Merry">Benchmarking Merry</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>7</fr:month>
                              <fr:day>4</fr:day>
                            </fr:date>
                            <fr:title text="Medium-to-small potatoes">Medium-to-small potatoes</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>I used <fr:link href="https://github.com/shellspec/shellbench" type="external">shellbench</fr:link> to understand where some of the performance pitfalls were coming from.</html:p>
                            <html:pre class="hilite">
                              <html:code>
                                <html:span class="sh-source">$ ./shellbench -s bash,zsh,msh sample/func.sh
</html:span>
                                <html:span class="sh-source">-----------------------------------------------------------------------------------
</html:span>
                                <html:span class="sh-source">name                                                     bash        zsh        msh
</html:span>
                                <html:span class="sh-source">-----------------------------------------------------------------------------------
</html:span>
                                <html:span class="sh-source">func.sh: no func                                      775,539  1,124,485      5,229
</html:span>
                                <html:span class="sh-source">func.sh: func                                         398,861    197,169     93,424
</html:span>
                                <html:span class="sh-source">-----------------------------------------------------------------------------------
</html:span>
                                <html:span class="sh-keyword-operator-glob">*</html:span>
                                <html:span class="sh-source"> count: number of executions per second
</html:span>
                              </html:code>
                            </html:pre>
                            <html:p>This particular benchmark first runs nothing (i.e. <html:code>:</html:code>) and then a function lookup and execution. Surprisingly <html:code>msh</html:code> is <html:em>slower</html:em> at doing <html:em>nothing</html:em>! I <html:code>perf</html:code>-ed a run of <html:code>msh test.sh</html:code> with just a single <html:code>:</html:code> in the file:</html:p>
                            <html:iframe width="100%|" height="400px" src="/bafkrmicucn54u6lmz2u3jky3sug4nxj7yhwjf3iscpfcax7ar4fwjl7gce.svg" />
                            <fr:tree show-metadata="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2026</fr:year>
                                  <fr:month>7</fr:month>
                                  <fr:day>4</fr:day>
                                </fr:date>
                                <fr:title text="Test built-in">Test built-in</fr:title>
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <html:p>After making various improvements to <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> that almost halved the memory usage (e.g., removing extraneous string manipulations, adding a fast-path to the <html:code>PATH</html:code> variable for resolving programs). I was still pretty far off the performance of these other shells. I decided to have a look at <html:code>dash</html:code> which has a simple implementation.</html:p>
                                <html:iframe width="100%|" height="400px" src="/bafkrmieljhv7prkf5rovr72f22v44fdizrszrmtn46feydg6phek2sac7a.svg" />
                                <html:p>This flame graph is for the following shell script:</html:p>
                                <html:pre class="hilite">
                                  <html:code>
                                    <html:span class="sh-entity-name-function">f</html:span>
                                    <html:span class="sh-meta-function"> </html:span>
                                    <html:span class="sh-punctuation-definition-arguments"><![CDATA[()]]></html:span>
                                    <html:span class="sh-meta-function"> </html:span>
                                    <html:span class="sh-punctuation-definition-group"><![CDATA[{]]></html:span>
                                    <html:span class="sh-meta-scope-group"> </html:span>
                                    <html:span class="sh-support-function-builtin">:</html:span>
                                    <html:span class="sh-keyword-operator-list">;</html:span>
                                    <html:span class="sh-meta-scope-group"> </html:span>
                                    <html:span class="sh-punctuation-definition-group"><![CDATA[}]]></html:span>
                                    <html:span class="sh-punctuation-definition-function">
</html:span>
                                    <html:span class="sh-keyword-control">while</html:span>
                                    <html:span class="sh-meta-scope-while-loop"> __count=</html:span>
                                    <html:span class="sh-punctuation-definition-string-begin"><![CDATA[$((]]></html:span>
                                    <html:span class="sh-punctuation-definition-variable">$</html:span>
                                    <html:span class="sh-variable-other-normal">__count</html:span>
                                    <html:span class="sh-keyword-operator-arithmetic">+</html:span>
                                    <html:span class="sh-constant-numeric-integer">1</html:span>
                                    <html:span class="sh-punctuation-definition-string-end"><![CDATA[))]]></html:span>
                                    <html:span class="sh-meta-scope-while-loop"> </html:span>
                                    <html:span class="sh-keyword-operator-list">&amp;&amp;</html:span>
                                    <html:span class="sh-meta-scope-while-loop"><![CDATA[ []]></html:span>
                                    <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                    <html:span class="sh-punctuation-definition-variable">$</html:span>
                                    <html:span class="sh-variable-other-normal">__count</html:span>
                                    <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                    <html:span class="sh-meta-scope-while-loop"><![CDATA[ -le 10000 ]]]></html:span>
                                    <html:span class="sh-keyword-operator-list">;</html:span>
                                    <html:span class="sh-meta-scope-while-loop"> </html:span>
                                    <html:span class="sh-keyword-control">do</html:span>
                                    <html:span class="sh-meta-scope-while-loop">
</html:span>
                                    <html:span class="sh-meta-scope-while-loop">	f
</html:span>
                                    <html:span class="sh-keyword-control">done</html:span>
                                    <html:span class="sh-source">
</html:span>
                                    <html:span class="sh-support-function-builtin">echo</html:span>
                                    <html:span class="sh-source"> </html:span>
                                    <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                    <html:span class="sh-string-quoted-double">count is </html:span>
                                    <html:span class="sh-punctuation-definition-variable">$</html:span>
                                    <html:span class="sh-variable-other-normal">__count</html:span>
                                    <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                    <html:span class="sh-source">
</html:span>
                                  </html:code>
                                </html:pre>
                                <html:p>And here are some rudimentary benchmarks:</html:p>
                                <html:pre class="hilite">
                                  <html:code>
                                    <html:span class="sh-source">$ </html:span>
                                    <html:span class="sh-keyword-other">time</html:span>
                                    <html:span class="sh-source"> -p dash test.sh
</html:span>
                                    <html:span class="sh-source">count is 10001
</html:span>
                                    <html:span class="sh-source">real 0.01
</html:span>
                                    <html:span class="sh-source">user 0.01
</html:span>
                                    <html:span class="sh-source">sys 0.00
</html:span>
                                    <html:span class="sh-source">$ </html:span>
                                    <html:span class="sh-keyword-other">time</html:span>
                                    <html:span class="sh-source"> -p msh test.sh
</html:span>
                                    <html:span class="sh-source">count is 10001
</html:span>
                                    <html:span class="sh-source">real 15.53
</html:span>
                                    <html:span class="sh-source">user 4.28
</html:span>
                                    <html:span class="sh-source">sys 12.28
</html:span>
                                  </html:code>
                                </html:pre>
                                <html:p>It turns out the massive slowdown is very simple to explain. In the <html:code>dash</html:code> flamegraph there is a <html:code>oexpr</html:code> stack; <fr:link href="https://git.kernel.org/pub/scm/utils/dash/dash.git/tree/src/bltin/test.c" type="external">which comes from the bltin/test.c</fr:link> file. <html:code>dash</html:code>, along with the other shells, does <html:em>not</html:em> spawn a process for the <html:code><![CDATA[[]]></html:code>-test command! Forcing <html:code>dash</html:code> to do use the binary <html:code><![CDATA[[]]></html:code> gives:</html:p>
                                <html:pre class="hilite">
                                  <html:code>
                                    <html:span class="sh-source">$ </html:span>
                                    <html:span class="sh-keyword-other">time</html:span>
                                    <html:span class="sh-source"> -p dash test.sh
</html:span>
                                    <html:span class="sh-source">count is 10001
</html:span>
                                    <html:span class="sh-source">real 7.55
</html:span>
                                    <html:span class="sh-source">user 3.95
</html:span>
                                    <html:span class="sh-source">sys 3.44
</html:span>
                                  </html:code>
                                </html:pre>
                                <html:p>Which is much more respectable in terms of performance compared to <html:code>msh</html:code>. Plenty of work to do though!</html:p>
                              </fr:mainmatter>
                            </fr:tree>
                            <fr:tree show-metadata="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2026</fr:year>
                                  <fr:month>7</fr:month>
                                  <fr:day>4</fr:day>
                                </fr:date>
                                <fr:title text="Parsing arithmetic expressions">Parsing arithmetic expressions</fr:title>
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <html:p>There was some obvious low-hanging fruit to help improve some of the performance differences. The first was pre-parsing arithmetic expressions. <fr:link href="github.com/colis-anr/morbig" type="external">Morbig</fr:link>, the static parser, does not implement arithmetic expression parsing; so <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> does it for us. Before, it was on-demand, as we encountered an expression of the form <html:code>$((&lt;e&gt;))</html:code>. Now, it happens up front. This should improve tight-loops.</html:p>
                              </fr:mainmatter>
                            </fr:tree>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>4</fr:day>
                        </fr:date>
                        <fr:title text="Writing">Writing</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>More on this soon, but I have started writing two separate papers bringing all of this work together.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>6</fr:month>
                      <fr:day>16</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/weekly-2026-w25/</fr:uri>
                    <fr:display-uri>weekly-2026-w25</fr:display-uri>
                    <fr:route>/weekly-2026-w25/</fr:route>
                    <fr:title text="Three weeks in the Shell">Three weeks in the Shell</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The last three weeks have been focused work on building <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>. In practice, I wanted to run the following two commands through <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>'s shell: <html:code>msh</html:code>:</html:p>
                    <html:pre><![CDATA[apt-get install debootstrap -y
debootstrap stable /stable-chroot http://deb.debian.org/debian/]]></html:pre>
                    <html:p>Seemingly innocuous. But both commands run <html:em>thousands</html:em> of lines of shell script. Whether that's <fr:link href="https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html" type="external">Debian package maintainer scripts</fr:link> or <fr:link href="https://salsa.debian.org/installer-team/debootstrap/-/blob/master/functions?ref_type=heads#L623" type="external">state-machines for processing package release files</fr:link>.</html:p>
                    <html:p>What follows is a handful of the bugs and the shell scripts that caused them.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>6</fr:month>
                          <fr:day>16</fr:day>
                        </fr:date>
                        <fr:title text="Field Splitting">Field Splitting</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>Edge-cases abound in the <fr:link href="/posixSpec/" title="IEEE/Open Group Standard for Information Technology--Portable Operating System Interface (POSIX™) Base Specifications, Issue 8" uri="https://patrick.sirref.org/posixSpec/" display-uri="posixSpec" type="local">POSIX shell specification</fr:link>; and field splitting is one of the most serious perpetrators. <html:em>Field splitting</html:em> happens after <html:em>word expansion</html:em>. It is a known footgun amongst shell script authors.</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="sh-source">$ count </html:span>
                            <html:span class="sh-punctuation-definition-subshell"><![CDATA[(]]></html:span>
                            <html:span class="sh-punctuation-definition-subshell"><![CDATA[)]]></html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-punctuation-definition-group"><![CDATA[{]]></html:span>
                            <html:span class="sh-meta-scope-group"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-meta-scope-group"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">Count: </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-special">#</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-group"> </html:span>
                            <html:span class="sh-punctuation-definition-group"><![CDATA[}]]></html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> FOO=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">hello world</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> count </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">FOO</html:span>
                            <html:span class="sh-source">
</html:span>
                            <html:span class="sh-source">Count: 2
</html:span>
                          </html:code>
                        </html:pre>
                        <html:p>Quoting variables that need expanding will prevent field splitting from taking place, but it is an easy thing to forget.</html:p>
                        <html:p>Field splitting uses the <html:code>IFS</html:code> (internal field separator) environment variable to determine how to do the splitting, and it comes with some extra rules beyond "split on these characters".</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="sh-source">$ IFS=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double"> </html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> FOO=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double"> hello    world</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">FOO</html:span>
                            <html:span class="sh-source">
</html:span>
                            <html:span class="sh-source">hello world
</html:span>
                            <html:span class="sh-source">$ IFS=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double"> </html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> FOO=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double"> hello    world</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">FOO</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-source">
</html:span>
                            <html:span class="sh-source"> hello    world
</html:span>
                            <html:span class="sh-source">$ IFS=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">:</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> FOO=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">a:b:c:</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">FOO</html:span>
                            <html:span class="sh-source">
</html:span>
                            <html:span class="sh-source">a b c
</html:span>
                            <html:span class="sh-source">$ IFS=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">:</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> FOO=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">a:b::c:d</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">FOO</html:span>
                            <html:span class="sh-source">
</html:span>
                            <html:span class="sh-source">a b  c d
</html:span>
                            <html:span class="sh-source">$ IFS=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">:</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> FOO=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">:a:b:c</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">FOO</html:span>
                            <html:span class="sh-source">
</html:span>
                            <html:span class="sh-source"> a b c
</html:span>
                            <html:span class="sh-source">$ IFS=</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> FOO=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">unset   IFS</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">FOO</html:span>
                            <html:span class="sh-source">
</html:span>
                            <html:span class="sh-support-function-builtin">unset</html:span>
                            <html:span class="sh-source">   IFS
</html:span>
                          </html:code>
                        </html:pre>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>6</fr:month>
                              <fr:day>16</fr:day>
                            </fr:date>
                            <fr:title text="Variable assignment">Variable assignment</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>How a shell stores variables also impacts field splitting. Naively, <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> stored variables as strings, but really they should be stored as their expanded form.</html:p>
                            <html:p>Consider this example of saving a function output in a variable called <html:code>base</html:code>.</html:p>
                            <html:pre class="hilite">
                              <html:code>
                                <html:span class="sh-entity-name-function">iter</html:span>
                                <html:span class="sh-meta-function"> </html:span>
                                <html:span class="sh-punctuation-definition-arguments"><![CDATA[()]]></html:span>
                                <html:span class="sh-meta-function"> </html:span>
                                <html:span class="sh-punctuation-definition-group"><![CDATA[{]]></html:span>
                                <html:span class="sh-meta-scope-group">
</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">a</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-meta-scope-group">
</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">b</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-meta-scope-group">
</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">c</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-meta-scope-group">
</html:span>
                                <html:span class="sh-punctuation-definition-group"><![CDATA[}]]></html:span>
                                <html:span class="sh-punctuation-definition-function">
</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-source">base=</html:span>
                                <html:span class="sh-punctuation-definition-string-begin"><![CDATA[$(]]></html:span>
                                <html:span class="sh-string-interpolated-dollar">iter</html:span>
                                <html:span class="sh-punctuation-definition-string-end"><![CDATA[)]]></html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-keyword-control">for</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-variable-other-loop">n</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-keyword-control">in</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-punctuation-definition-variable">$</html:span>
                                <html:span class="sh-variable-other-normal">base</html:span>
                                <html:span class="sh-keyword-operator-list">;</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-keyword-control">do</html:span>
                                <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                                <html:span class="sh-meta-scope-for-in-loop">  </html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">Got </html:span>
                                <html:span class="sh-punctuation-definition-variable">$</html:span>
                                <html:span class="sh-variable-other-normal">n</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                                <html:span class="sh-keyword-control">done</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-keyword-control">for</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-variable-other-loop">n</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-keyword-control">in</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-punctuation-definition-variable">$</html:span>
                                <html:span class="sh-variable-other-normal">base</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-keyword-operator-list">;</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-keyword-control">do</html:span>
                                <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                                <html:span class="sh-meta-scope-for-in-loop">  </html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">Got </html:span>
                                <html:span class="sh-punctuation-definition-variable">$</html:span>
                                <html:span class="sh-variable-other-normal">n</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                                <html:span class="sh-keyword-control">done</html:span>
                                <html:span class="sh-source">
</html:span>
                              </html:code>
                            </html:pre>
                            <html:p>Later, when we come to iterate across the fields of <html:code>$base</html:code> we wouldn't be able to reconstruct the intial fields that <html:code>$(iter)</html:code> produced if we simply saved the result as a string. Too much information would have been lost.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>6</fr:month>
                          <fr:day>16</fr:day>
                        </fr:date>
                        <fr:title text="Redirections">Redirections</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>Redirections control what file descriptors point to. Each redirection has a lifetime associated with it. For example: <html:code>cat &lt; README.md</html:code> really says "open <html:code>README.md</html:code> and execute the <html:code>cat</html:code> program mapping the process's FD <html:code>0</html:code> to the FD of <html:code>README.md</html:code>". When <html:code>cat</html:code> returns that redirection is no longer valid.</html:p>
                        <html:p>Other redirections are not so simple. Consider:</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="sh-source">$ </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">!dlrow olleh</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-keyword-operator-redirect">&gt;</html:span>
                            <html:span class="sh-source"> input.txt
</html:span>
                            <html:span class="sh-source">$ </html:span>
                            <html:span class="sh-punctuation-definition-subshell"><![CDATA[(]]></html:span>
                            <html:span class="sh-meta-scope-subshell">read line</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-subshell"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-meta-scope-subshell"> </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">line</html:span>
                            <html:span class="sh-punctuation-definition-subshell"><![CDATA[)]]></html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-keyword-operator-redirect">&lt;</html:span>
                            <html:span class="sh-source"> input.txt </html:span>
                            <html:span class="sh-keyword-operator-pipe">|</html:span>
                            <html:span class="sh-source"> rev
</html:span>
                            <html:span class="sh-source">hello world</html:span>
                            <html:span class="sh-keyword-operator-pipe">!</html:span>
                            <html:span class="sh-source">
</html:span>
                          </html:code>
                        </html:pre>
                        <html:p>There are lots of redirections here too. Firstly the standard input for everything inside the braced command (<html:code>read line2; echo $line</html:code>) should be the open file descriptor for <html:code>input.txt</html:code>. The standard output of the braced command should be the writing end of a pipe whose reading end is passed to <html:code>rev</html:code> as that process's standard input. The final standard output for <html:code>rev</html:code> should be unchanged from what it was originally (the shell's standard output).</html:p>
                        <html:p>Getting redirections right is hard, consider this snippet from the debootstrap scripts (all in the context of stdout and stderr pointing to a <html:code>debootstrap.log</html:code> file and file descriptor <html:code>4</html:code> pointing at the true stdout).</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="sh-keyword-control">for</html:span>
                            <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                            <html:span class="sh-variable-other-loop">m</html:span>
                            <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                            <html:span class="sh-keyword-control">in</html:span>
                            <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">MIRRORS</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-for-in-loop"> </html:span>
                            <html:span class="sh-keyword-control">do</html:span>
                            <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                            <html:span class="sh-meta-scope-for-in-loop">    pkgdest=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">TARGET</html:span>
                            <html:span class="sh-string-quoted-double">/</html:span>
                            <html:span class="sh-punctuation-definition-string-begin"><![CDATA[$(]]></html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">DLDEST</html:span>
                            <html:span class="sh-string-interpolated-dollar"> pkg </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">s</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-string-interpolated-dollar"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">c</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-string-interpolated-dollar"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">a</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-string-interpolated-dollar"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">m</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-string-interpolated-dollar"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">path</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-punctuation-definition-string-end"><![CDATA[)]]></html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                            <html:span class="sh-meta-scope-if-block">    </html:span>
                            <html:span class="sh-keyword-control">if</html:span>
                            <html:span class="sh-meta-scope-if-block"><![CDATA[ []]></html:span>
                            <html:span class="sh-keyword-operator-pipe">!</html:span>
                            <html:span class="sh-meta-scope-if-block"> -e </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">pkgdest</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-meta-scope-if-block"><![CDATA[ ]]]></html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-if-block"> </html:span>
                            <html:span class="sh-keyword-control">then</html:span>
                            <html:span class="sh-meta-scope-if-block"> </html:span>
                            <html:span class="sh-keyword-control">continue</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-if-block"> </html:span>
                            <html:span class="sh-keyword-control">fi</html:span>
                            <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                            <html:span class="sh-meta-scope-for-in-loop">    pkgs_to_get=</html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-string-begin"><![CDATA[$(]]></html:span>
                            <html:span class="sh-string-interpolated-dollar">download_debs </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">m</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-string-interpolated-dollar"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">pkgdest</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-string-interpolated-dollar"> </html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">pkgs_to_get</html:span>
                            <html:span class="sh-string-interpolated-dollar"> </html:span>
                            <html:span class="sh-keyword-operator-redirect">5&gt;&amp;1</html:span>
                            <html:span class="sh-string-interpolated-dollar"> </html:span>
                            <html:span class="sh-keyword-operator-redirect">1&gt;&amp;6</html:span>
                            <html:span class="sh-punctuation-definition-string-end"><![CDATA[)]]></html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                            <html:span class="sh-meta-scope-if-block">    </html:span>
                            <html:span class="sh-keyword-control">if</html:span>
                            <html:span class="sh-meta-scope-if-block"><![CDATA[ [ -z]]></html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-punctuation-definition-variable">$</html:span>
                            <html:span class="sh-variable-other-normal">pkgs_to_get</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-meta-scope-if-block"><![CDATA[ ]]]></html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-if-block"> </html:span>
                            <html:span class="sh-keyword-control">then</html:span>
                            <html:span class="sh-meta-scope-if-block"> </html:span>
                            <html:span class="sh-support-function-builtin">break</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-if-block"> </html:span>
                            <html:span class="sh-keyword-control">fi</html:span>
                            <html:span class="sh-meta-scope-for-in-loop">
</html:span>
                            <html:span class="sh-keyword-control">done</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-keyword-operator-redirect">6&gt;&amp;1</html:span>
                            <html:span class="sh-source">
</html:span>
                          </html:code>
                        </html:pre>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>6</fr:month>
                          <fr:day>16</fr:day>
                        </fr:date>
                        <fr:title text="More niche built-ins">More niche built-ins</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>As the dust begins to settle on the nuts and bolts of implementing a POSIX-ish shell, new challenges are allowed to emerge from deep within scripts.</html:p>
                        <html:p>One such challenge is the seemingly endless (I know, they're finite) shell built-ins! Whilst trying to run <fr:link href="https://wiki.debian.org/fakechroot" type="external">debootstrap using its <html:code>fakechroot</html:code> variant</fr:link>, I bumped into <html:code>getopts</html:code>... a whole command-line parsing shell built-in.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>6</fr:month>
                          <fr:day>16</fr:day>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/eio_mem/</fr:uri>
                        <fr:display-uri>eio_mem</fr:display-uri>
                        <fr:route>/eio_mem/</fr:route>
                        <fr:title text="An In-memory Filesystem for Eio ">An In-memory Filesystem for Eio </fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>Towards the end of last week and the beginning of this week, I threw together a prototype for an <html:em>in-memory filesystem</html:em> for <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>: <fr:link href="https://git.sirref.org/eio_mem" type="external">Eio_mem</fr:link>. Concretely, this provides a means for constructing an <html:code>Eio.Fs.dir_ty Eio.Path.t</html:code> value that is completely in-memory.</html:p>
                        <html:p>Thanks to <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>'s capability-first approach, any existing code implemented against the <html:code>_ Eio.Path.t</html:code> API should just work with the in-memory filesystem.</html:p>
                        <html:p>There's a convenient <html:code>Eio_mem.Fs.load</html:code> function that can take a path from one filesystem (most likely a normal one from <html:code>Eio_linux</html:code> or <html:code>Eio_posix</html:code>) and replicate it into the in-memory filesystem. For example, you might have a static web-server pointing to a directory like <html:code>"/var/www"</html:code>. The following might be the only change you need to make it completely in-memory (<fr:link href="https://github.com/mirage/ocaml-cohttp/blob/main/cohttp-eio/examples/server2.ml" type="external">example from ocaml-cohttp</fr:link>):</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="diff-source"><![CDATA[ let () =]]></html:span>
                            <html:span class="diff-source">   let port = ref 8080 in
</html:span>
                            <html:span class="diff-source">   Arg.parse
</html:span>
                            <html:span class="diff-source"><![CDATA[     [ ("-p", Arg.Set_int port, " Listening port number(8080 by default)") ]]]></html:span>
                            <html:span class="diff-source">     ignore "An HTTP/1.1 server";
</html:span>
                            <html:span class="diff-source">   Eio_main.run @@ fun env -&gt;
</html:span>
                            <html:span class="diff-punctuation-definition-inserted">+</html:span>
                            <html:span class="diff-markup-inserted">  Eio_mem.run @@ fun menv -&gt;
</html:span>
                            <html:span class="diff-source">   Eio.Switch.run @@ fun sw -&gt;
</html:span>
                            <html:span class="diff-punctuation-definition-deleted">-</html:span>
                            <html:span class="diff-markup-deleted"><![CDATA[  (* Restrict to current directory: *)]]></html:span>
                            <html:span class="diff-source">
</html:span>
                            <html:span class="diff-punctuation-definition-deleted">-</html:span>
                            <html:span class="diff-markup-deleted">  let htdocs = Eio.Stdenv.cwd env in
</html:span>
                            <html:span class="diff-punctuation-definition-inserted">+</html:span>
                            <html:span class="diff-markup-inserted"><![CDATA[  (* Restrict to in-memory current directory: *)]]></html:span>
                            <html:span class="diff-source">
</html:span>
                            <html:span class="diff-punctuation-definition-inserted">+</html:span>
                            <html:span class="diff-markup-inserted"><![CDATA[  Eio_mem.Fs.load ~filter (Eio.Stdenv.cwd env);]]></html:span>
                            <html:span class="diff-source">
</html:span>
                            <html:span class="diff-punctuation-definition-inserted">+</html:span>
                            <html:span class="diff-markup-inserted">  let htdocs = Eio.Stdenv.cwd menv in
</html:span>
                            <html:span class="diff-source">   let socket =
</html:span>
                            <html:span class="diff-source">     Eio.Net.listen env#net ~sw ~backlog:128 ~reuse_addr:true
</html:span>
                            <html:span class="diff-source"><![CDATA[       (`Tcp (Eio.Net.Ipaddr.V4.loopback, !port))]]></html:span>
                          </html:code>
                        </html:pre>
                        <html:p>The keen-eyed reader might have noticed the <html:code>filter</html:code> parameter. This can be used to ignore certain paths (here I ignored <html:code>.git</html:code> and <html:code>_build</html:code> which were adding substantial time to loading the filesystem).</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>6</fr:month>
                      <fr:day>4</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/weekly-2026-w23/</fr:uri>
                    <fr:display-uri>weekly-2026-w23</fr:display-uri>
                    <fr:route>/weekly-2026-w23/</fr:route>
                    <fr:title text="Using meio to debug Merry">Using meio to debug Merry</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>During a large rewrite of <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>, I introduced a regression causing certain shell programs to hang indefinitely. I thought it might be a good opportunity to try out <fr:link href="/meio/" title="Meio" uri="https://patrick.sirref.org/meio/" display-uri="meio" type="local">Meio</fr:link>.</html:p>
                    <html:p>First, let's look at a trace of <fr:link href="/meio/" title="Meio" uri="https://patrick.sirref.org/meio/" display-uri="meio" type="local">Meio</fr:link> from some real-world programs. For example: <html:code>meio -- msh -c "sleep 100"</html:code>.</html:p>
                    <html:img src="/bafkrmideu267e77ak6j5b7z2gda6nijipa7tfmz2r4ivsruktrhdzai3gi.gif" />
                    <html:p>One problem that comes up immediately from this example is that the tree hierarchy of tasks and cancellation contexts makes it tricky to reason about the logging. Here, we can see the pipeline's cancellation context clearly labelled <html:code>pipeline-id1</html:code>. This is an <html:code>Eio.Switch.t</html:code> for the pipeline <html:code>sleep 100</html:code>. The actual execution log for <html:code>sleep 100</html:code> bubbles back up to the main fiber (that has no name, so it is called <html:code>&lt;task&gt;</html:code>). The daemon fiber, for ensuring the spawned process is reaped, is attached to the switch and is displayed below it.</html:p>
                    <html:p><fr:link href="/meio/" title="Meio" uri="https://patrick.sirref.org/meio/" display-uri="meio" type="local">Meio</fr:link> has a long way to go. Most programs are too fast to be monitored in this way. Using something like <fr:link href="https://github.com/tokio-rs/console" type="external">tokio-console</fr:link>'s model might be a better idea here focusing less on the tree strucuture of the program, and more on the performance and monitoring of individual tasks. Without this, it turns out <fr:link href="/meio/" title="Meio" uri="https://patrick.sirref.org/meio/" display-uri="meio" type="local">Meio</fr:link> was not all that useful for debugging this specific issue (which ended up being some bad pipe management on my part).</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>28</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/weekly-2026-w17/</fr:uri>
                    <fr:display-uri>weekly-2026-w17</fr:display-uri>
                    <fr:route>/weekly-2026-w17/</fr:route>
                    <fr:title text="Shell forks revisited">Shell forks revisited</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Whilst I did get up to some other work last week, I decided to dedicate this weekly to <html:code>fork</html:code>-ing in the shell.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>4</fr:month>
                          <fr:day>28</fr:day>
                        </fr:date>
                        <fr:title text="Must we fork?">Must we fork?</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I have spent some time trying to figure out: can you implement a shell that never has to <html:code>fork</html:code> and run its own code (as opposed to <html:code>fork+exec</html:code>-ing, which is necessary)? There are, at least, two bits of POSIX shell semantics that make this hard: concurrency and redirects, particularly in the presence of shell built-ins.</html:p>
                        <html:p>Individual commands in a pipeline, according to the <fr:link href="/posixSpec/" title="IEEE/Open Group Standard for Information Technology--Portable Operating System Interface (POSIX™) Base Specifications, Issue 8" uri="https://patrick.sirref.org/posixSpec/" display-uri="posixSpec" type="local">POSIX specification</fr:link>, will have their standard input and output connected up before other redirections.</html:p>
                        <html:blockquote>
                          <html:p>The standard input, standard output, or both of a command shall be considered to be assigned by the pipeline before any redirection specified by redirection operators that are part of the command.</html:p>
                        </html:blockquote>
                        <html:p>Additionally:</html:p>
                        <html:blockquote>
                          <html:p>...each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment.</html:p>
                        </html:blockquote>
                        <html:p>Where a subshell is defined as:</html:p>
                        <html:blockquote>
                          <html:p>Subshell: A shell execution environment, distinguished from the main or current shell execution environment.</html:p>
                        </html:blockquote>
                        <html:p>We will note that subshell <fr:tex display="inline"><![CDATA[\neq ]]></fr:tex> child process. In practice, however, the two are used fairly interchangeably given the semantics of spawning a child process. Perhaps the two most crucial aspects of a given command in a subshell are that:</html:p>
                        <html:ol>
                          <html:li>
                            <html:p>It is run <html:em>in parallel</html:em> with the other commands.</html:p>
                          </html:li>
                          <html:li>
                            <html:p>It should be <fr:link href="https://en.wikipedia.org/wiki/Reentrancy_(computing)" type="external"><html:em>reentrant</html:em></fr:link>.</html:p>
                          </html:li>
                        </html:ol>
                        <html:p>In what follows we will assume that we are discussing a multi-command pipeline <fr:tex display="inline"><![CDATA[p]]></fr:tex>.</html:p>
                        <html:p>
                          <fr:tex display="block"><![CDATA[ \texttt {p} =  \texttt {cmd}_1 | ... | \texttt {cmd}_n \text { where } n \geq  2 ]]></fr:tex>
                        </html:p>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>4</fr:month>
                              <fr:day>28</fr:day>
                            </fr:date>
                            <fr:title text="Pipeline parallelism">Pipeline parallelism</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>The <fr:link href="/posixSpec/" title="IEEE/Open Group Standard for Information Technology--Portable Operating System Interface (POSIX™) Base Specifications, Issue 8" uri="https://patrick.sirref.org/posixSpec/" display-uri="posixSpec" type="local">POSIX specification</fr:link> does not mandate parallelism explicitly for commands in a pipeline. However, in practice the semantics of a pipeline necessitate concurrency at the very least.</html:p>
                            <html:p>Suppose we have <fr:tex display="inline"><![CDATA[\texttt {cmd}_1 | \texttt {cmd}_2]]></fr:tex> where <fr:tex display="inline"><![CDATA[\texttt {cmd}_1]]></fr:tex> produces an infinite amount of output (e.g., <html:code>cat /dev/urandom</html:code>) and <fr:tex display="inline"><![CDATA[\texttt {cmd}_2]]></fr:tex> consumes a finite amount of input (e.g., <fr:link href="https://github.com/dinosaure/hxd" type="external"><html:code>hxd-xxd -l100</html:code></fr:link>). What is the result of running this pipeline with the default POSIX shell options?</html:p>
                            <html:pre class="hilite">
                              <html:code>
                                <html:span class="sh-source">$ dash -c </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">cat /dev/urandom | hxd.xxd -l100</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-source">00000000: 5033 7981 ae44 d475 074c 5361 0a9e 3828  P3y..D.u.LSa..8</html:span>
                                <html:span class="sh-punctuation-definition-subshell"><![CDATA[(]]></html:span>
                                <html:span class="sh-meta-scope-subshell">
</html:span>
                                <html:span class="sh-meta-scope-subshell">00000010: f88c 1f9e 3b0e bcde 528a f78c b1e4 7195  ....</html:span>
                                <html:span class="sh-keyword-operator-list">;</html:span>
                                <html:span class="sh-meta-scope-subshell">...R.....q.
</html:span>
                                <html:span class="sh-meta-scope-subshell"><![CDATA[00000020: 16f2 8325 c90b 9310 539c af04 8289 c3a0  ...%....S.......]]></html:span>
                                <html:span class="sh-meta-scope-subshell">
</html:span>
                                <html:span class="sh-meta-scope-subshell">00000030: 57c5 680a 2c81 a999 71b6 708e 95df e720  W.h.,...q.p....
</html:span>
                                <html:span class="sh-meta-scope-subshell">00000040: 004c 407a 8365 9448 65c6 b435 bed2 4084  .L@z.e.He..5..@.
</html:span>
                                <html:span class="sh-meta-scope-subshell">00000050: 62ea 96ab 2b23 0385 f9d2 fc30 d090 1719  b...+#.....0....
</html:span>
                                <html:span class="sh-meta-scope-subshell">00000060: 68d1 c514                                h...
</html:span>
                                <html:span class="sh-meta-scope-subshell">cat: write error: Broken pipe
</html:span>
                              </html:code>
                            </html:pre>
                            <html:p>There are three factors that influence the pipeline's execution behaviour (i.e. what is done about the commands that are run and the exit status we return).</html:p>
                            <html:ol>
                              <html:li>
                                <html:p><html:code>pipefail</html:code>: With <html:code>pipefail</html:code> set to <html:code>false</html:code> (the default), the exit status of the pipeline is entirely decided upon by the exit status of the <html:em>rightmost</html:em> command (above <fr:tex display="inline"><![CDATA[\texttt {cmd}_2]]></fr:tex>). With <html:code>pipefail</html:code>, the pipe will exit with 0 if all commands exit with 0; otherwise the non-zero exit status of the <html:em>rightmost</html:em> command is taken.</html:p>
                              </html:li>
                              <html:li>
                                <html:p><html:code>!</html:code>: If the pipeline begins with <html:code>!</html:code> then this inverts the exit code in the way you might expect.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>All commands must terminate.</html:p>
                              </html:li>
                            </html:ol>
                            <html:p>Whilst in theory <fr:tex display="inline"><![CDATA[\texttt {cmd}_1]]></fr:tex> does not terminate, the termination of <fr:tex display="inline"><![CDATA[\texttt {cmd}_2]]></fr:tex> closes the reading end of the pipe resulting in the <html:code>Broken pipe</html:code> system error.</html:p>
                            <html:p>Let's replace <fr:tex display="inline"><![CDATA[\texttt {cmd}_1]]></fr:tex> with the following <html:em>compound command</html:em> that also produces, left to its own devices, infinite output on <html:code>stdout</html:code>.</html:p>
                            <html:pre class="hilite">
                              <html:code>
                                <html:span class="sh-keyword-control">while</html:span>
                                <html:span class="sh-meta-scope-while-loop"> </html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-meta-scope-while-loop"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">some bytes</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-keyword-operator-list">;</html:span>
                                <html:span class="sh-meta-scope-while-loop"> </html:span>
                                <html:span class="sh-keyword-control">do</html:span>
                                <html:span class="sh-meta-scope-while-loop">
</html:span>
                                <html:span class="sh-meta-scope-while-loop">  </html:span>
                                <html:span class="sh-support-function-builtin">:</html:span>
                                <html:span class="sh-meta-scope-while-loop">
</html:span>
                                <html:span class="sh-keyword-control">done</html:span>
                                <html:span class="sh-source"> </html:span>
                                <html:span class="sh-keyword-operator-pipe">|</html:span>
                                <html:span class="sh-source"> hxd.xxd -l100
</html:span>
                              </html:code>
                            </html:pre>
                            <html:p>In this example, we no longer have the luxury of being able to <html:code>fork</html:code> and <html:code>exec</html:code>. The compound command (the <html:code>while</html:code> loop) forces our hand -- we must rely on the internal execution logic of the shell to keep it going. How then do we prevent <fr:tex display="inline"><![CDATA[\texttt {cmd}_1]]></fr:tex> from blocking our shell from spawning <fr:tex display="inline"><![CDATA[\texttt {cmd}_2]]></fr:tex>?</html:p>
                            <html:p>For most shells, this is where they might <html:code>fork</html:code> themselves and allow the <html:code>while</html:code> loop to execute in the child. The parent continuing on. Alternatively, the work could continue on in a separate thread (in OCaml parlance, domain). Fibers (green threads, coroutines etc.) are only possible if there are a sufficient number of co-operative yields (which can be hard to track: any control flow or shell built-in would need to ensure they periodically yield to the other commands in the pipeline).</html:p>
                            <html:p>With that being said, it would seem we have workarounds to ensure the parallel aspects of pipelines are possible to build without forking the shell state itself.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>4</fr:month>
                              <fr:day>28</fr:day>
                            </fr:date>
                            <fr:title text="Command Reentrancy">Command Reentrancy</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>Command reentrancy deals with the fact that commands in a pipeline run in <html:em>subshells</html:em>. In practice, this means any <fr:tex display="inline"><![CDATA[\texttt {cmd}_i]]></fr:tex> should not impact the <html:em>execution environment</html:em> of any other <fr:tex display="inline"><![CDATA[\texttt {cmd}_j]]></fr:tex>. Commands may certainly interfere with one another: a rogue <html:code>rm</html:code> might remove a file that some other command was about to read or was in the middle of reading!</html:p>
                            <html:p><fr:tex display="inline"><![CDATA[\S 2.13]]></fr:tex> of the POSIX shell specification describes the execution environment. In <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> we lift this into the <html:code>ctx</html:code> type making it completely immutable; the only way to update the context is to destructively declare new fields, e.g., <html:code><![CDATA[{ ctx with cwd = "/home/bactrian" }]]></html:code>. All shell built-ins work directly from the context as opposed to any state that might <html:em>also</html:em> be kept by the process itself (e.g., we do not call <html:code>getcwd(3)</html:code> to expand <html:code>PWD</html:code>, but instead read it from the context).</html:p>
                            <html:p>Most state is handled nicely by this <html:em>functional</html:em> implementation of the shell; except open (or not) file descriptors. The <html:code>exec</html:code> built-in is particularly thorny in this regard:</html:p>
                            <html:blockquote>
                              <html:p>If exec is specified with no operands, any redirections associated with the exec command shall be made in the current shell execution environment.</html:p>
                            </html:blockquote>
                            <html:p>So, <html:code>exec 3&gt;&amp;1</html:code> says "in the current execution environment map file descriptor <html:code>3</html:code> to <html:code>stdout</html:code>" and <html:code>exec &gt; /dev/null</html:code> says "in the current execution environment map <html:code>stdout</html:code> to <html:code>/dev/null</html:code>. This is often used to silence anything writing to <html:code>stdout</html:code>.</html:p>
                            <html:pre class="hilite">
                              <html:code>
                                <html:span class="sh-entity-name-function">info</html:span>
                                <html:span class="sh-meta-function"> </html:span>
                                <html:span class="sh-punctuation-definition-arguments"><![CDATA[()]]></html:span>
                                <html:span class="sh-meta-function"> </html:span>
                                <html:span class="sh-punctuation-definition-group"><![CDATA[{]]></html:span>
                                <html:span class="sh-meta-scope-group">
</html:span>
                                <html:span class="sh-meta-scope-group">  </html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">INFO: </html:span>
                                <html:span class="sh-punctuation-definition-variable">$</html:span>
                                <html:span class="sh-variable-other-positional">1</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-keyword-operator-redirect">&gt;&amp;3</html:span>
                                <html:span class="sh-meta-scope-group">
</html:span>
                                <html:span class="sh-punctuation-definition-group"><![CDATA[}]]></html:span>
                                <html:span class="sh-punctuation-definition-function">
</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-support-function-builtin">exec</html:span>
                                <html:span class="sh-source"> </html:span>
                                <html:span class="sh-keyword-operator-redirect">3&gt;&amp;1</html:span>
                                <html:span class="sh-source"> </html:span>
                                <html:span class="sh-keyword-operator-redirect">&gt;</html:span>
                                <html:span class="sh-source"> /dev/null
</html:span>
                                <html:span class="sh-source">info </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">Starting up server...</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-source"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">Some noisy program spamming STDOUT</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-source">info </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">All is quiet...</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-source">
</html:span>
                              </html:code>
                            </html:pre>
                            <html:p>If we are not running shell built-ins inside new child processes, then we must lift the file descriptor table into the context as well and <html:em>disallow</html:em> any two built-ins to run in parallel. Consider this example:</html:p>
                            <html:pre class="hilite">
                              <html:code>
                                <html:span class="sh-support-function-builtin">exec</html:span>
                                <html:span class="sh-source"> </html:span>
                                <html:span class="sh-keyword-operator-redirect">&lt;</html:span>
                                <html:span class="sh-source"> ./hello.txt
</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-keyword-control">while</html:span>
                                <html:span class="sh-meta-scope-while-loop"> </html:span>
                                <html:span class="sh-support-function-builtin">read</html:span>
                                <html:span class="sh-meta-scope-while-loop"> line</html:span>
                                <html:span class="sh-keyword-operator-list">;</html:span>
                                <html:span class="sh-meta-scope-while-loop"> </html:span>
                                <html:span class="sh-keyword-control">do</html:span>
                                <html:span class="sh-meta-scope-while-loop">
</html:span>
                                <html:span class="sh-meta-scope-while-loop">  </html:span>
                                <html:span class="sh-support-function-builtin">echo</html:span>
                                <html:span class="sh-meta-scope-while-loop"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">Got </html:span>
                                <html:span class="sh-punctuation-definition-variable">$</html:span>
                                <html:span class="sh-variable-other-normal">line</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-meta-scope-while-loop"> </html:span>
                                <html:span class="sh-keyword-operator-redirect">&gt;&amp;2</html:span>
                                <html:span class="sh-meta-scope-while-loop">
</html:span>
                                <html:span class="sh-keyword-control">done</html:span>
                                <html:span class="sh-source"> </html:span>
                                <html:span class="sh-keyword-operator-pipe">|</html:span>
                                <html:span class="sh-source"> </html:span>
                                <html:span class="sh-punctuation-definition-subshell"><![CDATA[(]]></html:span>
                                <html:span class="sh-meta-scope-subshell">exec </html:span>
                                <html:span class="sh-keyword-operator-redirect">&lt;</html:span>
                                <html:span class="sh-meta-scope-subshell"> ./world.txt</html:span>
                                <html:span class="sh-keyword-operator-list">;</html:span>
                                <html:span class="sh-meta-scope-subshell"> cat</html:span>
                                <html:span class="sh-punctuation-definition-subshell"><![CDATA[)]]></html:span>
                                <html:span class="sh-source">
</html:span>
                              </html:code>
                            </html:pre>
                            <html:p>If we allow <html:code>exec</html:code> to <html:em>change</html:em> the set of open file descriptors of the shell process directly, then individual commands in the pipeline are no longer re-entrant. The pipeline here is not being used to pipe bytes from one command to another, but instead to expose concurrency and the subshell behaviour.</html:p>
                            <html:p>The second <html:code>exec &lt; ./world.txt</html:code> has no impact on the currently opened file on <html:code>stdin</html:code>, the while loop continues to read <html:code>./hello.txt</html:code>. This is straightforward to implement with <html:code>fork</html:code> as you can <html:code>dup2</html:code> any files you need. The bookkeeping and isolation is all provided by the POSIX process semantics. Without <html:code>fork</html:code>, the file descriptors would have to be saved and restored on every suspension and resumption to provide an illusion of isolation.</html:p>
                            <html:p>We could relax our rule to "disallow any two built-ins to run in parallel" by taking a lock on the file descriptor table, but considering the lock is held from the point of resumption until the next suspension it might not achieve very much in practice.</html:p>
                            <html:p>Some of the intricacies of scheduling are also covered in <fr:link href="/greenberg2020smoosh/" title="Executable formal semantics for the POSIX shell" uri="https://patrick.sirref.org/greenberg2020smoosh/" display-uri="greenberg2020smoosh" type="local">Michael Greenberg's <html:em>An executable and formal semantics of the POSIX shell</html:em></fr:link>.</html:p>
                            <html:blockquote>
                              <html:p>To motivate the question, consider the following two pipelines:</html:p>
                              <html:p>(1) <html:code>while true; do echo 5; done | true</html:code></html:p>
                              <html:p>(2) <html:code><![CDATA[while true; do echo 5; done | { read x; echo $((x+42)); }]]></html:code></html:p>
                              <html:p>Both pipelines spawn two processes, both of which use shell builtins exclusively: neither of these pipelines needs to make an <html:code>execve</html:code> system call (though some systems may implement true or echo as executables, Smoosh and most shells build them in).</html:p>
                            </html:blockquote>
                            <html:p>Scheduling is an opaque part of the <fr:link href="/posixSpec/" title="IEEE/Open Group Standard for Information Technology--Portable Operating System Interface (POSIX™) Base Specifications, Issue 8" uri="https://patrick.sirref.org/posixSpec/" display-uri="posixSpec" type="local">POSIX specification</fr:link>. Indeed, as we have argued here, there is <html:em>no</html:em> semantics for scheduling. Here is a similar pipeline run through a script that <html:code>strace</html:code>s for <html:code>clone</html:code> and <html:code>fork</html:code> calls on various shells:</html:p>
                            <html:pre><![CDATA[% ./test/check_fork.sh "while echo 5; do : ; done | true"
bash  3
dash  3
yash  1 
zsh   1
ksh   1
ash   3]]></html:pre>
                            <html:p>It might make an interesting use case for effects in OCaml -- whilst we can certainly piggyback on <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>'s existing suspension mechanisms, this is slightly different in that we need to ensure some preconditions are true before resuming certain computations. Fiber-local state is insufficient as programs implicitly depend on global state of the process (in particular the FD table). In this sense, we need some form of suspension-resumption hooks.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>3</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/weekly-2026-w14/</fr:uri>
                    <fr:display-uri>weekly-2026-w14</fr:display-uri>
                    <fr:route>/weekly-2026-w14/</fr:route>
                    <fr:title text="Forking in Shells &amp; Library Maintenance">Forking in Shells &amp; Library Maintenance</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>This week, <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> got close to executing <html:code>apt-get install ca-certificates</html:code> and running Debian's <html:code>debootstrap</html:code> scripts correctly. <fr:link href="https://patrick.sirref.org/nathan/" type="external">Nathan</fr:link> and I released <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> <html:code>0.38.0</html:code>, I added support to <fr:link href="https://github.com/geocaml/ocaml-proj" type="external">ocaml-proj</fr:link> for compiling to the browser and I fixed a long-standing bug in <fr:link href="https://github.com/patricoferris/hilite" type="external">hilite</fr:link>.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>4</fr:month>
                          <fr:day>3</fr:day>
                        </fr:date>
                        <fr:title text="Forking in Merry">Forking in Merry</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>So far, <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> has managed to support many features of the POSIX shell specification without needing to do a <html:code>fork(2)</html:code> without an <html:code>exec</html:code>. Or, to put it another way, all the forking that <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> does, will only be followed by running C code. This is actually a feature of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>'s <html:code>Process</html:code> API. It is required to make process execution safe in the context of multiple domains in OCaml (mostly due to ensuring consistency within the garbage collector). However, it is perfectly okay to <html:code>fork</html:code> and run OCaml code provided there is only a single domain.</html:p>
                        <html:p>In a shell, many features of the shell language require that commands (or built-ins, function applications etc.) execute within a <html:code>subshell</html:code>. The specification does not go into detail about how shells should implement this, but many choose to <html:code>fork</html:code> in order to preserve some state in the parent (for example, the file descriptor table). Some shells try to minimise the number of forks as an optimisation. The <fr:link href="/korn1996korn/" title="The New Korn Shell" uri="https://patrick.sirref.org/korn1996korn/" display-uri="korn1996korn" type="local">korn shell (ksh)</fr:link> is one such shell.</html:p>
                        <html:blockquote>
                          <html:p>Using the notation <html:code>$(command)</html:code> will cause <html:code>command</html:code> to execute in a subshell of the current ksh. In many instances, ksh will not actually fork/exec a subshell when command is a built-in or a shell function.</html:p>
                        </html:blockquote>
                        <html:p>By trying to adhere to Multicore OCaml's "<html:em>thou shalt not fork</html:em>" commandment, <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is much more similar to <html:code>ksh</html:code> in this regard. However, whenever there is an interaction with a shell built-in and semantics that need a child process, things get tricky very quickly. Consider the following:</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="sh-keyword-control">while</html:span>
                            <html:span class="sh-meta-scope-while-loop"> </html:span>
                            <html:span class="sh-support-function-builtin">echo</html:span>
                            <html:span class="sh-meta-scope-while-loop"> </html:span>
                            <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                            <html:span class="sh-string-quoted-double">hello</html:span>
                            <html:span class="sh-punctuation-definition-string-end">"</html:span>
                            <html:span class="sh-keyword-operator-list">;</html:span>
                            <html:span class="sh-meta-scope-while-loop"> </html:span>
                            <html:span class="sh-keyword-control">do</html:span>
                            <html:span class="sh-meta-scope-while-loop">
</html:span>
                            <html:span class="sh-meta-scope-while-loop">  </html:span>
                            <html:span class="sh-support-function-builtin">:</html:span>
                            <html:span class="sh-meta-scope-while-loop">
</html:span>
                            <html:span class="sh-keyword-control">done</html:span>
                            <html:span class="sh-source"> </html:span>
                            <html:span class="sh-keyword-operator-pipe">|</html:span>
                            <html:span class="sh-source"> head -n 3
</html:span>
                          </html:code>
                        </html:pre>
                        <html:p>We have a mix of shell built-ins, normal commands, a compound command (the <html:code>while</html:code> loop) and a pipeline. Each individual command in the pipeline requires you to run them in a subshell and set them up <html:em>before</html:em> executing them. Without a <html:code>fork</html:code> for that first command, you may end up looping forever which is not the intended behaviour here. I had a good conversation with <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> about the implications of this for reproducibility.</html:p>
                        <html:p>For now, I have started implementing a <html:code>fork</html:code> for some of the shell features whilst still trying to maintain the functional core of the implementation.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>4</fr:month>
                          <fr:day>3</fr:day>
                        </fr:date>
                        <fr:title text="An OCaml 5.5 compatible Ppxlib">An OCaml 5.5 compatible Ppxlib</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> and I released an OCaml 5.5 compatible version of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>.</html:p>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>3</fr:month>
                              <fr:day>30</fr:day>
                            </fr:date>
                            <fr:uri>https://patrick.sirref.org/ppxlib-release-0-38-0/</fr:uri>
                            <fr:display-uri>ppxlib-release-0-38-0</fr:display-uri>
                            <fr:route>/ppxlib-release-0-38-0/</fr:route>
                            <fr:title text="Ppxlib Releases › 0.38.0 "><fr:link href="/ppxlib-releases/" title="Ppxlib Releases" uri="https://patrick.sirref.org/ppxlib-releases/" display-uri="ppxlib-releases" type="local">Ppxlib Releases</fr:link> › 0.38.0 </fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p><fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> and I <fr:link href="https://github.com/ocaml/opam-repository/pull/29563" type="external">released ppxlib.0.38.0</fr:link> last week. Its main feature is full <html:em>migration</html:em> support for the upcoming OCaml 5.5 compiler (currently in its <html:code>alpha3</html:code> release). This means supporting the handful of new features landing in OCaml 5.5: <fr:link href="/modular-explicits/" title="Modular Explicits in OCaml" uri="https://patrick.sirref.org/modular-explicits/" display-uri="modular-explicits" type="local">modular explicits</fr:link>, external type declarations and arbitrary "local" structure items.</html:p>
                            <html:p>As <fr:link href="https://patrick.sirref.org/nathenreb/" type="external">Nathan</fr:link> and I continue to find a plausible maintenance story for <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>, <fr:link href="https://patrick.sirref.org/nathenreb/" type="external">Nathan</fr:link> has opened <fr:link href="https://github.com/ocaml/ocaml/issues/14668" type="external">an issue on the OCaml compiler to discuss the idea of adding additional extension points to the language</fr:link>.</html:p>
                            <html:p>This comes from the desire to be able to store encoded versions of new OCaml features inside older abstract syntax trees.</html:p>
                            <html:p>There are also some nice bug fixes in there too:</html:p>
                            <html:ul>
                              <html:li>
                                <html:p><fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/613" type="external">A potential OOM</fr:link> loop has now been removed.</html:p>
                              </html:li>
                              <html:li>
                                <html:p>
                                  <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/619" type="external">Locations have been restored to long identifiers!</fr:link>
                                </html:p>
                              </html:li>
                            </html:ul>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>4</fr:month>
                          <fr:day>3</fr:day>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/ocaml-proj-virt/</fr:uri>
                        <fr:display-uri>ocaml-proj-virt</fr:display-uri>
                        <fr:route>/ocaml-proj-virt/</fr:route>
                        <fr:title text="Browser support for ocaml-proj ">Browser support for ocaml-proj </fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>A while ago <fr:link href="https://github.com/geocaml/ocaml-proj" type="external">I built some "modern" bindings to PROJ4 in OCaml</fr:link>. After reading <fr:link href="https://patrick.sirref.org/jonludlam/" type="external">Jon Ludlam</fr:link>'s <fr:link href="https://jon.recoil.org/blog/2026/03/weeknotes-2026-12.html" type="external">weeknotes</fr:link> (and speaking with him and <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link>, I thought it might be nice to add a Javascript backend to those bindings). This was relatively straight-forward using <fr:link href="https://dune.readthedocs.io/en/stable/virtual-libraries.html" type="external">Dune's virtual libraries</fr:link> and is <fr:link href="https://github.com/geocaml/ocaml-proj/blob/main/src/js/proj.ml" type="external">available on Github</fr:link>.</html:p>
                        <html:p>With virtual libraries, your own data analysis could (if you wished) depend solely on the <html:code>proj</html:code> library and later choose to either link it with <html:code>proj.c</html:code> or <html:code>proj.js</html:code> depending on where the analysis is being deployed.</html:p>
                        <html:p>I briefly looked at WASM support, but quickly realised there was not much appetite for it and trying to compile around the C FFI was going to be hard.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>4</fr:month>
                          <fr:day>3</fr:day>
                        </fr:date>
                        <fr:title text="Hilite updates">Hilite updates</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>Since I helped <fr:link href="https://ocaml.org/" type="external">relaunch the ocaml.org</fr:link> website a few years ago, I have maintained <fr:link href="https://github.com/patricoferris/hilite" type="external">hilite</fr:link>, a tool for doing build-time syntax highligting.</html:p>
                        <html:p>It is being used on the <fr:link href="https://ocaml.org/" type="external">ocaml.org</fr:link> website, <fr:link href="https://github.com/xhtmlboi/yocaml/blob/45858f4b25730149dae3735e7fcdb9111ac1f9eb/yocaml_markdown.opam#L18" type="external">in yocaml_markdown</fr:link> and also in <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael's</fr:link> <fr:link href="https://github.com/mdales/webplats/blob/cf0ea95a66bae52f02a00739eb02564fc94183ee/webplats.opam#L19" type="external">webplats</fr:link> (when it works...).</html:p>
                        <html:p>And it was <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> who led me to finally fixing and adding syntax highlighting support for Python and Go. Once I was on this roll, I finally took a look at fixing the long-standing bug of trying to highlight ocaml-mdx code, like the following:</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="ocaml-mdx-hash">#</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-float">50.123</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-mdx-hash">#</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">1</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-string-quoted-double">"</html:span>
                            <html:span class="ocaml-string-quoted-double">file.ml</html:span>
                            <html:span class="ocaml-string-quoted-double">"</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                            <html:span class="ocaml-source">
</html:span>
                          </html:code>
                        </html:pre>
                        <html:p>In fact, this code now highlights fine, but was the source of the bug. The syntax highlighting grammer confuses the ocaml-mdx <html:code>#</html:code> as a toplevel directive and trouble ensues.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>3</fr:month>
                      <fr:day>30</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/weekly-2026-w13/</fr:uri>
                    <fr:display-uri>weekly-2026-w13</fr:display-uri>
                    <fr:route>/weekly-2026-w13/</fr:route>
                    <fr:title text="Ppxlib release and Merry updates">Ppxlib release and Merry updates</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>3</fr:month>
                          <fr:day>30</fr:day>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/ppxlib-release-0-38-0/</fr:uri>
                        <fr:display-uri>ppxlib-release-0-38-0</fr:display-uri>
                        <fr:route>/ppxlib-release-0-38-0/</fr:route>
                        <fr:title text="Ppxlib Releases › 0.38.0 "><fr:link href="/ppxlib-releases/" title="Ppxlib Releases" uri="https://patrick.sirref.org/ppxlib-releases/" display-uri="ppxlib-releases" type="local">Ppxlib Releases</fr:link> › 0.38.0 </fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> and I <fr:link href="https://github.com/ocaml/opam-repository/pull/29563" type="external">released ppxlib.0.38.0</fr:link> last week. Its main feature is full <html:em>migration</html:em> support for the upcoming OCaml 5.5 compiler (currently in its <html:code>alpha3</html:code> release). This means supporting the handful of new features landing in OCaml 5.5: <fr:link href="/modular-explicits/" title="Modular Explicits in OCaml" uri="https://patrick.sirref.org/modular-explicits/" display-uri="modular-explicits" type="local">modular explicits</fr:link>, external type declarations and arbitrary "local" structure items.</html:p>
                        <html:p>As <fr:link href="https://patrick.sirref.org/nathenreb/" type="external">Nathan</fr:link> and I continue to find a plausible maintenance story for <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>, <fr:link href="https://patrick.sirref.org/nathenreb/" type="external">Nathan</fr:link> has opened <fr:link href="https://github.com/ocaml/ocaml/issues/14668" type="external">an issue on the OCaml compiler to discuss the idea of adding additional extension points to the language</fr:link>.</html:p>
                        <html:p>This comes from the desire to be able to store encoded versions of new OCaml features inside older abstract syntax trees.</html:p>
                        <html:p>There are also some nice bug fixes in there too:</html:p>
                        <html:ul>
                          <html:li>
                            <html:p><fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/613" type="external">A potential OOM</fr:link> loop has now been removed.</html:p>
                          </html:li>
                          <html:li>
                            <html:p>
                              <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/619" type="external">Locations have been restored to long identifiers!</fr:link>
                            </html:p>
                          </html:li>
                        </html:ul>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>3</fr:month>
                          <fr:day>30</fr:day>
                        </fr:date>
                        <fr:title text="Merry updates">Merry updates</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>It turns out writing a POSIX(ish) shell is hard; at least, there is a vast number of slightly obscure features that one needs to support. I think this is surprising because most people writing shell scripts write simple shell scripts; scripts that use a much smaller subset of features. In the same breath, those same developers are likely to use something like <html:code>apt-get install bash</html:code> which runs a plethora of more advanced (and non-POSIX) shell scripts!</html:p>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>3</fr:month>
                              <fr:day>30</fr:day>
                            </fr:date>
                            <fr:title text="Exec redirects">Exec redirects</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>In a shell script, you can use the built-in command <html:code>exec</html:code> to replace the current process with a new one (e.g. <html:code>exec vim</html:code>). However, there is a <fr:link href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_21" type="external"><html:em>different</html:em> mode of operation</fr:link> for <html:code>exec</html:code>:</html:p>
                            <html:blockquote>
                              <html:p>If exec is specified with no operands, any redirections associated with the exec command shall be made in the current shell execution environment.</html:p>
                            </html:blockquote>
                            <html:p>One of my litmus tests for <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is the <fr:link href="https://wiki.debian.org/Debootstrap" type="external">Debian debootstrap scripts</fr:link> (h/t <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link>). One thing that it does is the following:</html:p>
                            <html:pre class="hilite">
                              <html:code>
                                <html:span class="sh-entity-name-function">err</html:span>
                                <html:span class="sh-meta-function"> </html:span>
                                <html:span class="sh-punctuation-definition-arguments"><![CDATA[()]]></html:span>
                                <html:span class="sh-meta-function"> </html:span>
                                <html:span class="sh-punctuation-definition-group"><![CDATA[{]]></html:span>
                                <html:span class="sh-meta-scope-group">
</html:span>
                                <html:span class="sh-meta-scope-group">  </html:span>
                                <html:span class="sh-support-function-builtin">printf</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-punctuation-definition-string-begin">"</html:span>
                                <html:span class="sh-string-quoted-double">err </html:span>
                                <html:span class="sh-punctuation-definition-variable">$</html:span>
                                <html:span class="sh-variable-other-positional">1</html:span>
                                <html:span class="sh-punctuation-definition-string-end">"</html:span>
                                <html:span class="sh-meta-scope-group"> </html:span>
                                <html:span class="sh-keyword-operator-redirect">&gt;&amp;4</html:span>
                                <html:span class="sh-meta-scope-group">
</html:span>
                                <html:span class="sh-punctuation-definition-group"><![CDATA[}]]></html:span>
                                <html:span class="sh-punctuation-definition-function">
</html:span>
                                <html:span class="sh-source">
</html:span>
                                <html:span class="sh-support-function-builtin">exec</html:span>
                                <html:span class="sh-source"> </html:span>
                                <html:span class="sh-keyword-operator-redirect">4&gt;&amp;1</html:span>
                                <html:span class="sh-source"> 
</html:span>
                              </html:code>
                            </html:pre>
                            <html:p>A lot of detail has been elided for clarity. <html:code>exec 4&gt;&amp;1</html:code> sets up a redirection for the shell's execution environment in which file descriptor <html:code>4</html:code> is now an alias for standard output. So, writing to <html:code>4</html:code> (by redirecting a command's standard output to <html:code>4</html:code> i.e. <html:code>&gt;&amp;4</html:code>) will output to where standard output is going (most likely the terminal).</html:p>
                            <html:p>For this to work, shell's must <fr:link href="https://www.man7.org/linux/man-pages/man2/dup.2.html" type="external"><html:code>dup2</html:code></fr:link> the relevant file descriptors which have the following condition:</html:p>
                            <html:blockquote>
                              <html:p>If the file descriptor newfd was previously open, it is closed before being reused; the close is performed silently (i.e., any errors during the close are not reported by dup2()).</html:p>
                            </html:blockquote>
                            <html:p>This is all very well, unless your program has an important file already open that happens to have file descriptor <html:code>4</html:code>. The <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> Linux and POSIX backends suffer from this problem. Both make use of a file-based synchronisation mechanism for waking up the eventloop should another domain push a completion to the scheduler's run queue. On Linux this is <fr:link href="https://github.com/ocaml-multicore/eio/blob/c44ee5ce96c120b7ccc23a12d241dc8672e2888f/lib_eio_linux/sched.ml#L501" type="external">via an eventfd</fr:link> and in <fr:link href="https://github.com/ocaml-multicore/eio/blob/c44ee5ce96c120b7ccc23a12d241dc8672e2888f/lib_eio_posix/sched.ml#L20" type="external">POSIX, a pipe</fr:link>.</html:p>
                            <html:p>This <html:code>dup2</html:code> will close the <html:code>eventfd</html:code> and will likely grind Eio to a halt (or an <html:code>assert false</html:code>). For now, I have resorted to vendoring <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> and moving the <html:code>eventfd</html:code> file descriptors to higher values, though I <fr:link href="https://github.com/ocaml-multicore/eio/pull/836" type="external">have opened a PR to make this more configurable</fr:link>. This bug is quite easy to write up... it was not so easy to find!</html:p>
                            <html:p>As a random example, consider the <html:code>debconf/confmodule</html:code> <fr:link href="https://sources.debian.org/src/debconf/1.5.77/confmodule/" type="external">script</fr:link> which offers very little room for a buggy implementation!</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>3</fr:month>
                          <fr:day>30</fr:day>
                        </fr:date>
                        <fr:title text="Outreachy">Outreachy</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>The presentations from the demonstrations for this round of Outreachy are now online!</html:p>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>2</fr:month>
                              <fr:day>9</fr:day>
                            </fr:date>
                            <fr:uri>https://patrick.sirref.org/outreachy-ocaml-tiff/</fr:uri>
                            <fr:display-uri>outreachy-ocaml-tiff</fr:display-uri>
                            <fr:route>/outreachy-ocaml-tiff/</fr:route>
                            <fr:title text="Write support in OCaml TIFF library">Write support in OCaml TIFF library</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>I am mentoring <fr:link href="/tambe-salome/" title="Tambe Salome" uri="https://patrick.sirref.org/tambe-salome/" display-uri="tambe-salome" type="local">Tambe Salome</fr:link> during the December 2025 Outreachy round to add support for writing TIFF files in the <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link> library.</html:p>
                            <html:p>You can now see the video of the demonstration day presentation:</html:p>
                            <html:div style="text-align: center">
<html:iframe title="Outreachy Demo Day December 2025 Round" width="560" height="315" src="https://watch.ocaml.org/videos/embed/8aUqMhFvhQGq4WJLH3ukjA?start=1h18m33s" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" />
</html:div>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>3</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/weekly-2026-w12/</fr:uri>
                    <fr:display-uri>weekly-2026-w12</fr:display-uri>
                    <fr:route>/weekly-2026-w12/</fr:route>
                    <fr:title text="A POSIX Shell in OCaml">A POSIX Shell in OCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Long time, no weekly. Since the start of this year I have been building a POSIX shell in OCaml called <html:code>msh</html:code> (with the underlying library called <html:code>Merry</html:code>). <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is available online now.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>3</fr:month>
                          <fr:day>19</fr:day>
                        </fr:date>
                        <fr:title text="A POSIX(ish) shell in OCaml">A POSIX(ish) shell in OCaml</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is a POSIX(ish) in OCaml. It uses  <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> alongside <fr:link href="github.com/colis-anr/morbig" type="external">Morbig</fr:link> (a static parser for POSIX shell).</html:p>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>3</fr:month>
                              <fr:day>19</fr:day>
                            </fr:date>
                            <fr:title text="Why another (POSIX) shell?">Why another (POSIX) shell?</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>Shells have been around for a long time. In my research on the notion of <html:em>metashell</html:em> I wrote about Louis Pouzin originally coining the term:</html:p>
                            <fr:tree show-metadata="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2025</fr:year>
                                  <fr:month>5</fr:month>
                                  <fr:day>19</fr:day>
                                </fr:date>
                                <fr:uri>https://patrick.sirref.org/pouzin-shell/</fr:uri>
                                <fr:display-uri>pouzin-shell</fr:display-uri>
                                <fr:route>/pouzin-shell/</fr:route>
                                <fr:title text="Metashells › Louis Pouzin's &quot;SHELL&quot; "><fr:link href="/weekly-2025-05-12/" title="Metashells" uri="https://patrick.sirref.org/weekly-2025-05-12/" display-uri="weekly-2025-05-12" type="local">Metashells</fr:link> › Louis Pouzin's "SHELL" </fr:title>
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <html:p>I spent some time reading <fr:link href="/pouzin-shell-2013/" title="The Origin of the Shell" uri="https://patrick.sirref.org/pouzin-shell-2013/" display-uri="pouzin-shell-2013" type="local">part of the multics design documentation</fr:link> this week. Louis Pouzin coined the term "SHELL" in this document, and I was reminded yet again just how important it is to be a good writer even as a "computer science researcher". For example, this excerpt from the requirements section of the document</html:p>
                                <html:blockquote>
                                  <html:p>The previous definitions imply that a command MUST be designed while keeping in mind the user, sitting at his console, wondering about what might be going on, mistyping or forgetting arguments, even if fully aware of the conventions, and possibly interfering with the command by hasty quits, carriage returns, and other temperamental reactions.</html:p>
                                </html:blockquote>
                                <html:p>And then later, when defining the "SHELL".</html:p>
                                <html:blockquote>
                                  <html:p>We may envision a common procedure called automatically by the supervisor whenever a user types in some message at his console, at a time when he has no other process in active execution under console control (presently called command level). This procedure acts as an interface between console messages and subroutine. The purpose of such a procedure is to create a medium of exchange into which one could activate any procedure, <html:em>inside of another program if it were called</html:em>. Hereafter, for simplification, we shall refer to that procedure as the "SHELL".</html:p>
                                </html:blockquote>
                                <html:p>It still surprises how little the undergraduate degree in computer science at <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">Cambridge</fr:link> focuses on writing skills.</html:p>
                              </fr:mainmatter>
                            </fr:tree>
                            <html:p>I built <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> exploring the idea of a shell-like interface that allowed users to <html:em>undo</html:em> their shell actions (amongst other cool tricks). Unfortunately <html:em>shell-like</html:em> is not enough. <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> cut many corners to masquerade as a shell (e.g. appending <html:code>env</html:code> to understand how a command may have altered the execution environment). I felt it was necessary to make <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> a "SHELL"! To do that, I needed a solid foundation to build on.</html:p>
                            <html:p><html:code>msh</html:code>, the POSIX shell that comes with <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>, is by no means POSIX-complete in terms of features. But it is my <fr:link href="https://github.com/patricoferris/nixos/blob/e0faf870f76710d4a75ace775f333c88f1321c5a/modules/default.nix#L59" type="external">daily driver at this point</fr:link>. It includes a pure OCaml rewrite of <fr:link href="github.com/antirez/linenoise" type="external">linenoise</fr:link> (a small, self-contained alternative to the venerable <html:code>readline</html:code>) called <fr:link href="https://tangled.org/patrick.sirref.org/bruit" type="external">bruit</fr:link>.</html:p>
                            <html:p>If you have <html:code>docker</html:code> installed on your machine, you can take it for a spin today:</html:p>
                            <html:pre><![CDATA[docker run -it --rm patrickferris/msh]]></html:pre>
                            <html:p>The <html:code>patrickferris/msh</html:code> docker image is just for trying it out. It is based on the OCaml 5.3 alpine image.</html:p>
                            <html:p>Alternatively, you can build <html:code>msh</html:code> from source and have it available in your opam switch.</html:p>
                            <html:pre><![CDATA[opam pin git+https://tangled.org/patrick.sirref.org/merry]]></html:pre>
                            <html:p>There are many small paper cuts left to patch over, but most of it is porcelain (e.g. <html:code>ctrl+left-arrow</html:code> for moving in <fr:link href="https://tangled.org/patrick.sirref.org/bruit" type="external">bruit</fr:link>). Unfortunately, these are the kinds of things that you will <html:em>immediately</html:em> stumble upon.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>3</fr:month>
                              <fr:day>19</fr:day>
                            </fr:date>
                            <fr:title text="What makes Merry different?">What makes Merry different?</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>Nothing.</html:p>
                            <html:p><fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is supposed to be a solid, POSIX-ish base to build on. Unfortunaltely, as it turns out, the subset of features from the POSIX specification that people <html:em>actually use</html:em>... is pretty much all of it. Every possible redirection, variable expansion, shell built-in and compound command make some appearance. Not to mention the non-POSIX bits of shell we all take for granted (e.g. <html:code>&amp;&gt;</html:code>-redirection).</html:p>
                            <html:p><fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> and <html:code>msh</html:code> are useable. You will most likely find bugs if you use them. If, when using <html:code>msh</html:code>, you find something obscure happening you can enable debug mode either my setting the variable <html:code>MSH_DEBUG</html:code> or by invoking <html:code>msh</html:code> with <html:code>-v -v</html:code>.</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                        <fr:tree show-metadata="false" numbered="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2026</fr:year>
                              <fr:month>3</fr:month>
                              <fr:day>19</fr:day>
                            </fr:date>
                            <fr:title text="What's next?">What's next?</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>It is soon time to combine <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> and <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> into the time-travelling, POSIX-ish shell that I have been trying to build since I first started working on <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>.</html:p>
                            <html:p>For this to be successful, I need <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> to be able to pass plenty of tests and right now that involves trying to install plenty of packages using tools like <html:code>apk</html:code> and <html:code>apt</html:code>.</html:p>
                            <fr:tree show-metadata="false" numbered="false">
                              <fr:frontmatter>
                                <fr:authors>
                                  <fr:author>
                                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                                  </fr:author>
                                </fr:authors>
                                <fr:date>
                                  <fr:year>2026</fr:year>
                                  <fr:month>3</fr:month>
                                  <fr:day>19</fr:day>
                                </fr:date>
                                <fr:title text="Shell MRDT">Shell MRDT</fr:title>
                              </fr:frontmatter>
                              <fr:mainmatter>
                                <html:p>What I am particularly interested in reasoning about, is the <fr:link href="https://tangled.org/patrick.sirref.org/merry/blob/main/src/lib/eval.ml#L22" type="external">execution context</fr:link> in <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>. This value, alongside the file-system, constitutes a fairly deep understanding of the state that changes in each step of a shell's evaluation loop.</html:p>
                                <html:p>This was, in terms of <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>, the missing piece for truly building some kind of <fr:link href="/mrdts/" title="Mergeable Replicated Data Type Implementation" uri="https://patrick.sirref.org/mrdts/" display-uri="mrdts" type="local">MRDT</fr:link> across shell sessions.</html:p>
                              </fr:mainmatter>
                            </fr:tree>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>3</fr:month>
                          <fr:day>19</fr:day>
                        </fr:date>
                        <fr:title text="TIFF in OCaml">TIFF in OCaml</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I picked up from the excellent <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> work of <fr:link href="https://patrick.sirref.org/tambe salome/" type="external">Tambe Salome</fr:link> in getting write-support in <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link>. We are getting closer to the kind of API I envisaged in this latest round of refinement and review.</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="ocaml-keyword-other">let</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">/</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">=</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Eio</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Path</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">/</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-keyword">let</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-entity-name-function-binding">checkerboard</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">~</html:span>
                            <html:span class="ocaml-source">size</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">=</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">  </html:span>
                            <html:span class="ocaml-keyword">let</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-entity-name-function-binding">v</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">=</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source">zeros</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source">uint8</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[[|]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">size</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">size</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[|]]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">in</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">  </html:span>
                            <html:span class="ocaml-keyword">for</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-entity-name-function-binding">row</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">=</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">0</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">to</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">size</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">-</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">1</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">do</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">    </html:span>
                            <html:span class="ocaml-keyword">for</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-entity-name-function-binding">col</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">=</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">0</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">to</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">size</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">-</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">1</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">do</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">      </html:span>
                            <html:span class="ocaml-keyword-other">if</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                            <html:span class="ocaml-source">row</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">+</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">col</html:span>
                            <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">mod</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">2</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">=</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">0</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">then</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source">set_item</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[[]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">row</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">col</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[]]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">254</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">v</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">    </html:span>
                            <html:span class="ocaml-keyword-other">done</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">  </html:span>
                            <html:span class="ocaml-keyword-other">done</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">  </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source">to_bigarray</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">v</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-keyword-other">let</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-language-unit"><![CDATA[()]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">=</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">  </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Eio_posix</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source">run</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">@@</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">fun</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">env</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">  </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Tiff_eio</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source">with_open_out</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                            <html:span class="ocaml-source">env</html:span>
                            <html:span class="ocaml-keyword-other">#</html:span>
                            <html:span class="ocaml-source">cwd</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">/</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-string-quoted-double">"</html:span>
                            <html:span class="ocaml-string-quoted-double">example.tiff</html:span>
                            <html:span class="ocaml-string-quoted-double">"</html:span>
                            <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">@@</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">fun</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">w</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">  </html:span>
                            <html:span class="ocaml-keyword">let</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-entity-name-function-binding">tif</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-operator">=</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Tiff</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source">make</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                            <html:span class="ocaml-source">checkerboard</html:span>
                            <html:span class="ocaml-source"> ~</html:span>
                            <html:span class="ocaml-source">size</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                            <html:span class="ocaml-constant-numeric-decimal-integer">256</html:span>
                            <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-keyword-other">in</html:span>
                            <html:span class="ocaml-source">
</html:span>
                            <html:span class="ocaml-source">  </html:span>
                            <html:span class="ocaml-constant-language-capital-identifier">Tiff</html:span>
                            <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                            <html:span class="ocaml-source">to_file</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">tif</html:span>
                            <html:span class="ocaml-source"> </html:span>
                            <html:span class="ocaml-source">w</html:span>
                            <html:span class="ocaml-source">
</html:span>
                          </html:code>
                        </html:pre>
                        <html:img src="/bafkrmiaqqczj5lemda5ijfjtjsyldbhmveu3btfvoa7rpt5k4dvdejjuhu.png" />
                        <html:p>I have also been extremely pleased to see further external collaborators appearing:</html:p>
                        <html:ul>
                          <html:li>
                            <html:p><fr:link href="https://github.com/geocaml/ocaml-tiff/pull/63" type="external">Nicolas</fr:link> helping out with metadata maintainence.</html:p>
                          </html:li>
                          <html:li>
                            <html:p><fr:link href="https://github.com/geocaml/ocaml-tiff/pull/62" type="external">Virgile</fr:link> adding support for reading multi-image TIFF files.</html:p>
                          </html:li>
                        </html:ul>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>12</fr:month>
                      <fr:day>15</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/weekly-2025-w50/</fr:uri>
                    <fr:display-uri>weekly-2025-w50</fr:display-uri>
                    <fr:route>/weekly-2025-w50/</fr:route>
                    <fr:title text="Merry Shell(e)y">Merry Shell(e)y</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Aside from a serious amount of admin, last week I decided to spend a majority of my time thinking about shells.</html:p>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>12</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:title text="What is a shell?">What is a shell?</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>There is no single definition of what a shell is or isn't.</html:p>
                        <html:blockquote />
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>12</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/ai-blues/</fr:uri>
                        <fr:display-uri>ai-blues</fr:display-uri>
                        <fr:route>/ai-blues/</fr:route>
                        <fr:title text="AI Blues ">AI Blues </fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>Undoubtedly last week, I suffered a severe case of "AI blues" (for lack of a better description).</html:p>
                        <html:p>I have been doing some thinking, trying to distil my own thoughts on what aspects of <html:em>vibecoding</html:em> seem to irk me so much. Ultimately, it seems it is more about attitudes than anything else.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>12</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:title text="Exploitative">Exploitative</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>Increasingly, I am finding that other people's vibecoded work <html:em>is</html:em> my problem. I have been an active participant in OCaml's <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">outreachy</fr:link> work for going on five years now, and a problem mentors have to face is deciding the appropriate amount of help to give to your intern when they come to you with questions. More than likely, you could answer with specifics and solve the problem at hand. However, this doesn't scale very well and doesn't help your intern learn where else they may look for answers (e.g. <fr:link href="https://patrick.sirref.org/dune.readthedocs.io" type="external">Dune's documentation</fr:link>, a project's README page, <fr:link href="https://ocaml.org/packages" type="external">OCaml's package explorer</fr:link>, heck even just using some simple CLI tools!) or how they might go about debugging a certain problem.</html:p>
                        <html:p>LLMs, in my experience, make this problem worse. When they come up short, they can leave their programmer higher and drier than they would be had they hit a problem on their own. There is an inertia to understanding problems now that there's lots of code lying around. Turning to your colleagues has a few problems that it didn't before:</html:p>
                        <html:ol>
                          <html:li>
                            <html:p>Your colleagues don't know whose understanding they are correcting: yours or the LLMs?</html:p>
                          </html:li>
                          <html:li>
                            <html:p>If it is the latter, there seems to me to be an exploitative quality to even asking for help until you yourself know what's going wrong.</html:p>
                          </html:li>
                        </html:ol>
                        <fr:tree show-metadata="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                              <fr:month>12</fr:month>
                              <fr:day>15</fr:day>
                            </fr:date>
                            <fr:title text="Technological Accelerationism">Technological Accelerationism</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>There is no doubt that LLMs are pretty good at writing large amounts of okay code. The generation of this code, and often subsequent publishing of it, completely outpaces the ability to maintain it.</html:p>
                            <html:p>Programmers may be able to release ten times more libraries than they could before, but at the moment, they certainly cannot maintain ten times more libraries than they could before.</html:p>
                            <html:ol>
                              <html:li />
                              <html:li>
                                <html:p>Scale --</html:p>
                              </html:li>
                            </html:ol>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2026</fr:year>
              <fr:month>3</fr:month>
              <fr:day>19</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2026-w12/</fr:uri>
            <fr:display-uri>weekly-2026-w12</fr:display-uri>
            <fr:route>/weekly-2026-w12/</fr:route>
            <fr:title text="A POSIX Shell in OCaml">A POSIX Shell in OCaml</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Long time, no weekly. Since the start of this year I have been building a POSIX shell in OCaml called <html:code>msh</html:code> (with the underlying library called <html:code>Merry</html:code>). <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is available online now.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="A POSIX(ish) shell in OCaml">A POSIX(ish) shell in OCaml</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is a POSIX(ish) in OCaml. It uses  <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> alongside <fr:link href="github.com/colis-anr/morbig" type="external">Morbig</fr:link> (a static parser for POSIX shell).</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>3</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="Why another (POSIX) shell?">Why another (POSIX) shell?</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Shells have been around for a long time. In my research on the notion of <html:em>metashell</html:em> I wrote about Louis Pouzin originally coining the term:</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>5</fr:month>
                          <fr:day>19</fr:day>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/pouzin-shell/</fr:uri>
                        <fr:display-uri>pouzin-shell</fr:display-uri>
                        <fr:route>/pouzin-shell/</fr:route>
                        <fr:title text="Metashells › Louis Pouzin's &quot;SHELL&quot; "><fr:link href="/weekly-2025-05-12/" title="Metashells" uri="https://patrick.sirref.org/weekly-2025-05-12/" display-uri="weekly-2025-05-12" type="local">Metashells</fr:link> › Louis Pouzin's "SHELL" </fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I spent some time reading <fr:link href="/pouzin-shell-2013/" title="The Origin of the Shell" uri="https://patrick.sirref.org/pouzin-shell-2013/" display-uri="pouzin-shell-2013" type="local">part of the multics design documentation</fr:link> this week. Louis Pouzin coined the term "SHELL" in this document, and I was reminded yet again just how important it is to be a good writer even as a "computer science researcher". For example, this excerpt from the requirements section of the document</html:p>
                        <html:blockquote>
                          <html:p>The previous definitions imply that a command MUST be designed while keeping in mind the user, sitting at his console, wondering about what might be going on, mistyping or forgetting arguments, even if fully aware of the conventions, and possibly interfering with the command by hasty quits, carriage returns, and other temperamental reactions.</html:p>
                        </html:blockquote>
                        <html:p>And then later, when defining the "SHELL".</html:p>
                        <html:blockquote>
                          <html:p>We may envision a common procedure called automatically by the supervisor whenever a user types in some message at his console, at a time when he has no other process in active execution under console control (presently called command level). This procedure acts as an interface between console messages and subroutine. The purpose of such a procedure is to create a medium of exchange into which one could activate any procedure, <html:em>inside of another program if it were called</html:em>. Hereafter, for simplification, we shall refer to that procedure as the "SHELL".</html:p>
                        </html:blockquote>
                        <html:p>It still surprises how little the undergraduate degree in computer science at <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">Cambridge</fr:link> focuses on writing skills.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <html:p>I built <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> exploring the idea of a shell-like interface that allowed users to <html:em>undo</html:em> their shell actions (amongst other cool tricks). Unfortunately <html:em>shell-like</html:em> is not enough. <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> cut many corners to masquerade as a shell (e.g. appending <html:code>env</html:code> to understand how a command may have altered the execution environment). I felt it was necessary to make <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> a "SHELL"! To do that, I needed a solid foundation to build on.</html:p>
                    <html:p><html:code>msh</html:code>, the POSIX shell that comes with <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>, is by no means POSIX-complete in terms of features. But it is my <fr:link href="https://github.com/patricoferris/nixos/blob/e0faf870f76710d4a75ace775f333c88f1321c5a/modules/default.nix#L59" type="external">daily driver at this point</fr:link>. It includes a pure OCaml rewrite of <fr:link href="github.com/antirez/linenoise" type="external">linenoise</fr:link> (a small, self-contained alternative to the venerable <html:code>readline</html:code>) called <fr:link href="https://tangled.org/patrick.sirref.org/bruit" type="external">bruit</fr:link>.</html:p>
                    <html:p>If you have <html:code>docker</html:code> installed on your machine, you can take it for a spin today:</html:p>
                    <html:pre><![CDATA[docker run -it --rm patrickferris/msh]]></html:pre>
                    <html:p>The <html:code>patrickferris/msh</html:code> docker image is just for trying it out. It is based on the OCaml 5.3 alpine image.</html:p>
                    <html:p>Alternatively, you can build <html:code>msh</html:code> from source and have it available in your opam switch.</html:p>
                    <html:pre><![CDATA[opam pin git+https://tangled.org/patrick.sirref.org/merry]]></html:pre>
                    <html:p>There are many small paper cuts left to patch over, but most of it is porcelain (e.g. <html:code>ctrl+left-arrow</html:code> for moving in <fr:link href="https://tangled.org/patrick.sirref.org/bruit" type="external">bruit</fr:link>). Unfortunately, these are the kinds of things that you will <html:em>immediately</html:em> stumble upon.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>3</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="What makes Merry different?">What makes Merry different?</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Nothing.</html:p>
                    <html:p><fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> is supposed to be a solid, POSIX-ish base to build on. Unfortunaltely, as it turns out, the subset of features from the POSIX specification that people <html:em>actually use</html:em>... is pretty much all of it. Every possible redirection, variable expansion, shell built-in and compound command make some appearance. Not to mention the non-POSIX bits of shell we all take for granted (e.g. <html:code>&amp;&gt;</html:code>-redirection).</html:p>
                    <html:p><fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> and <html:code>msh</html:code> are useable. You will most likely find bugs if you use them. If, when using <html:code>msh</html:code>, you find something obscure happening you can enable debug mode either my setting the variable <html:code>MSH_DEBUG</html:code> or by invoking <html:code>msh</html:code> with <html:code>-v -v</html:code>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>3</fr:month>
                      <fr:day>19</fr:day>
                    </fr:date>
                    <fr:title text="What's next?">What's next?</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>It is soon time to combine <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> and <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> into the time-travelling, POSIX-ish shell that I have been trying to build since I first started working on <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>.</html:p>
                    <html:p>For this to be successful, I need <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link> to be able to pass plenty of tests and right now that involves trying to install plenty of packages using tools like <html:code>apk</html:code> and <html:code>apt</html:code>.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2026</fr:year>
                          <fr:month>3</fr:month>
                          <fr:day>19</fr:day>
                        </fr:date>
                        <fr:title text="Shell MRDT">Shell MRDT</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>What I am particularly interested in reasoning about, is the <fr:link href="https://tangled.org/patrick.sirref.org/merry/blob/main/src/lib/eval.ml#L22" type="external">execution context</fr:link> in <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>. This value, alongside the file-system, constitutes a fairly deep understanding of the state that changes in each step of a shell's evaluation loop.</html:p>
                        <html:p>This was, in terms of <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>, the missing piece for truly building some kind of <fr:link href="/mrdts/" title="Mergeable Replicated Data Type Implementation" uri="https://patrick.sirref.org/mrdts/" display-uri="mrdts" type="local">MRDT</fr:link> across shell sessions.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>19</fr:day>
                </fr:date>
                <fr:title text="TIFF in OCaml">TIFF in OCaml</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I picked up from the excellent <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> work of <fr:link href="https://patrick.sirref.org/tambe salome/" type="external">Tambe Salome</fr:link> in getting write-support in <fr:link href="/ocaml-tiff/" title="ocaml-tiff" uri="https://patrick.sirref.org/ocaml-tiff/" display-uri="ocaml-tiff" type="local">ocaml-tiff</fr:link>. We are getting closer to the kind of API I envisaged in this latest round of refinement and review.</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="ocaml-keyword-other">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">/</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Path</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">/</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">checkerboard</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">~</html:span>
                    <html:span class="ocaml-source">size</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">v</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">zeros</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">uint8</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[[|]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">size</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">size</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[|]]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">in</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword">for</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">row</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">0</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">to</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">size</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">1</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">do</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">    </html:span>
                    <html:span class="ocaml-keyword">for</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">col</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">0</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">to</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">size</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">1</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">do</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">      </html:span>
                    <html:span class="ocaml-keyword-other">if</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source">row</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">+</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">col</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">mod</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">2</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">0</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">then</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">set_item</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[[]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">row</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">col</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[]]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">254</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">v</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">    </html:span>
                    <html:span class="ocaml-keyword-other">done</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword-other">done</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">to_bigarray</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">v</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword-other">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-unit"><![CDATA[()]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio_posix</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">run</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">@@</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">fun</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">env</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Tiff_eio</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">with_open_out</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source">env</html:span>
                    <html:span class="ocaml-keyword-other">#</html:span>
                    <html:span class="ocaml-source">cwd</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">/</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-string-quoted-double">"</html:span>
                    <html:span class="ocaml-string-quoted-double">example.tiff</html:span>
                    <html:span class="ocaml-string-quoted-double">"</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">@@</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">fun</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">w</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">tif</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Tiff</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">make</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source">checkerboard</html:span>
                    <html:span class="ocaml-source"> ~</html:span>
                    <html:span class="ocaml-source">size</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">256</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">in</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Tiff</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">to_file</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">tif</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">w</html:span>
                    <html:span class="ocaml-source">
</html:span>
                  </html:code>
                </html:pre>
                <html:img src="/bafkrmiaqqczj5lemda5ijfjtjsyldbhmveu3btfvoa7rpt5k4dvdejjuhu.png" />
                <html:p>I have also been extremely pleased to see further external collaborators appearing:</html:p>
                <html:ul>
                  <html:li>
                    <html:p><fr:link href="https://github.com/geocaml/ocaml-tiff/pull/63" type="external">Nicolas</fr:link> helping out with metadata maintainence.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/geocaml/ocaml-tiff/pull/62" type="external">Virgile</fr:link> adding support for reading multi-image TIFF files.</html:p>
                  </html:li>
                </html:ul>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2026</fr:year>
              <fr:month>2</fr:month>
              <fr:day>9</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/fellowship-roundup/</fr:uri>
            <fr:display-uri>fellowship-roundup</fr:display-uri>
            <fr:route>/fellowship-roundup/</fr:route>
            <fr:title text="Fellowship Roundup">Fellowship Roundup</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>9</fr:day>
                </fr:date>
                <fr:title text="Overview">Overview</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>February is the final month of my current six-month fellowship work with <fr:link href="https://tarides.com/" type="external">Tarides</fr:link>. A lot of the work can be summarised by reading the <fr:link href="/ocaml-blog/" title="Patrick's OCaml Blog" uri="https://patrick.sirref.org/ocaml-blog/" display-uri="ocaml-blog" type="local">roundups</fr:link> (see <fr:link href="/ocaml-roundup-october-2025/" title="OCaml Roundup: October 2025" uri="https://patrick.sirref.org/ocaml-roundup-october-2025/" display-uri="ocaml-roundup-october-2025" type="local">October</fr:link>, <fr:link href="/ocaml-roundup-november-2025/" title="OCaml Roundup: November 2025" uri="https://patrick.sirref.org/ocaml-roundup-november-2025/" display-uri="ocaml-roundup-november-2025" type="local">November</fr:link>, <fr:link href="/ocaml-roundup-december-2025/" title="OCaml Roundup: December 2025" uri="https://patrick.sirref.org/ocaml-roundup-december-2025/" display-uri="ocaml-roundup-december-2025" type="local">December</fr:link> and <fr:link href="/ocaml-roundup-january-2026/" title="OCaml Roundup: January 2026" uri="https://patrick.sirref.org/ocaml-roundup-january-2026/" display-uri="ocaml-roundup-january-2026" type="local">January</fr:link>). I have been writing throughout the fellowship. However, they do not quite capture all the work I have been doing.</html:p>
                <html:p>Below, I pick individual projects and expand on them more holistically rather than pointing at individual PRs or issues.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Ppxlib">Ppxlib</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Most of my time over the past six months has been devoted to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> maintenance. A large proportion of this time has been solo development work. <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> is a cornerstone library of the OCaml ecosystem (whether people like it or not).</html:p>
                    <html:pre><![CDATA[$ opam list --depends-on=ppxlib --recursive | wc -l
2030]]></html:pre>
                    <html:p>Moreover, it is completely invaluable to Jane Street too. Like other AST-based tools (e.g. ocamlformat, merlin), <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> must follow a regular release schedule to support newer compilers. During the years of multicore OCaml development, <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> maintenance was a little easier as the Parsetree rarely changed. However, since then, the same cannot be said. Since OCaml 5.2, here are just some of the Parsetree changes:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Functions are represented according to their arity.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Local module opens on types.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Effect syntax.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Modular explicits.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>External types.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Locations for all parts of long identifiers.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Labeled tuples.</html:p>
                      </html:li>
                    </html:ul>
                    <html:p>In a perfect world, each of these require a codec for serialising the feature into ASTs that do not support the feature, plenty of tests and new <html:code>Ast_builder</html:code>/<html:code>Ast_pattern</html:code> functions for using the feature. <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> and I have been managing pretty well I would say, though we are not getting any technical debt work done.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Outreachy">Outreachy</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>As the OCaml coordinator for <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> I have been running the latest December 2025 round. We are lucky to have <html:em>four</html:em> projects on the go!</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Thibaut Mattio is mentoring two projects: <fr:link href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#raven-create-a-monitoring-dashboard-for-deep-learn" type="external">an ML dashboard for Raven</fr:link> and <fr:link href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#create-an-oxcaml-backend-for-raven" type="external">an OxCaml backend for Raven</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p><fr:link href="https://github.com/xvw" type="external">Xvw</fr:link> is mentoring a <fr:link href="https://github.com/yocaml/" type="external">Yocaml</fr:link> <fr:link href="https://www.outreachy.org/outreachy-december-2025-internship-cohort/communities/ocaml/#improve-yocaml-error-reporting-and-data-model" type="external">project</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>I am <fr:link href="/outreachy-ocaml-tiff/" title="Write support in OCaml TIFF library" uri="https://patrick.sirref.org/outreachy-ocaml-tiff/" display-uri="outreachy-ocaml-tiff" type="local">mentoring</fr:link> a <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link> project.</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Eio">Eio</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>During my work on tools like <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> I have made a few improvements to <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/821" type="external">A draft PR for incremental reading of directories</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/803" type="external">New fork actions for processes: setgid, setuid and process groups</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/823" type="external">Utility functions for overriding standard environments</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/822" type="external">Fixing documentation</fr:link>.</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="OxCaml">OxCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I have enjoyed my work on OxCaml went it has happend. I think a few tools have been useful including the <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">try-oxcaml</fr:link> work. <fr:link href="/dra27/" title="David Allsopp" uri="https://patrick.sirref.org/dra27/" display-uri="dra27" type="local">David</fr:link> and I also had fun at <fr:link href="/icfp-2025/" title="ICFP 2025" uri="https://patrick.sirref.org/icfp-2025/" display-uri="icfp-2025" type="local">ICFP</fr:link> discussing some quick experiments related to <fr:link href="/icfp-oxcaml-uring/" title="OCaml Roundup: October 2025 › OxCaml Experiments " uri="https://patrick.sirref.org/icfp-oxcaml-uring/" display-uri="icfp-oxcaml-uring" type="local">io_uring and OxCaml</fr:link>.</html:p>
                    <html:p>One road-blocker here is the comparative amount of time spent trying to keep the OxCaml ecosystem working. Given my limited time working on fellowship projects, the rate of change of OxCaml (including the opam ecosystem) meant most of the time was spent making it just work, not exploring or experimenting with the features themselves. I think this has got better in recent months and perhaps jumping back in I would be surprised at the progress that has been made there.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Forester">Forester</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><fr:link href="https://tarides.org/" type="external">Tarides</fr:link> are funding some work on <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link>. This site uses <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link> by way of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> and I have spent some time working on these tools during the fellowship.</html:p>
                    <html:p>This includes a <html:code>bytesrw</html:code>-based <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">bibtex</fr:link> library in OCaml that could be released soon.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Papers">Papers</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I had the great fortune of attending <fr:link href="https://patrick.sirref.org/ifcp-2025/" type="external">ICFP</fr:link> where I presented two talks and was co-author on a few others too.</html:p>
                    <html:hr />
                    <fr:tree show-metadata="false" expanded="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/David J. Scott" type="external">David J. Scott</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Ryan T. Gibb" type="external">Ryan T. Gibb</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Thomas Gazagnaire/" type="external">Thomas Gazagnaire</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/madhavapeddy2025docker/</fr:uri>
                        <fr:display-uri>madhavapeddy2025docker</fr:display-uri>
                        <fr:route>/madhavapeddy2025docker/</fr:route>
                        <fr:title text="Functional Networking for Millions of Docker Desktops (Experience Report)">Functional Networking for Millions of Docker Desktops (Experience Report)</fr:title>
                        <fr:taxon>Reference</fr:taxon>
                        <fr:meta name="external">https://dl.acm.org/doi/10.1145/3747525</fr:meta>
                        <fr:meta name="journal">Proc. ACM Program. Lang.</fr:meta>
                        <fr:meta name="doi">10.1145/3747525</fr:meta>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <fr:tree show-metadata="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/David J. Scott" type="external">David J. Scott</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Ryan T. Gibb" type="external">Ryan T. Gibb</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Thomas Gazagnaire/" type="external">Thomas Gazagnaire</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                            </fr:date>
                            <fr:title text="Abstract">Abstract</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>
	Docker is a developer tool used by millions of developers to build, share
	and run software stacks. The Docker Desktop clients for Mac and Windows
	have long used a novel combination of virtualisation and OCaml unikernels
	to seamlessly run Linux containers on these non-Linux hosts.

	We reflect on a decade of shipping this functional OCaml code into
	production across hundreds of millions of developer desktops, and discuss
	the lessons learnt from our experiences in integrating OCaml deeply into
	the container architecture that now drives much of the global cloud. We
	conclude by observing just how good a fit for systems programming that the
	unikernel approach has been, particularly when combined with the OCaml
	module and type system.
</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" expanded="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/ferris2025scientific_programming/</fr:uri>
                        <fr:display-uri>ferris2025scientific_programming</fr:display-uri>
                        <fr:route>/ferris2025scientific_programming/</fr:route>
                        <fr:title text="What we talk about when we talk about scientific programming">What we talk about when we talk about scientific programming</fr:title>
                        <fr:taxon>Reference</fr:taxon>
                        <fr:meta name="external">https://watch.eeg.cl.cam.ac.uk/w/aYXqXLtgQawYMjVXjSQtjx</fr:meta>
                        <fr:meta name="doi" />
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <fr:tree show-metadata="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                            </fr:date>
                            <fr:title text="Abstract">Abstract</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>
	Programming for the planet undoubtedly involves programming
	scientifically, but what kind of programming are we talking about
	and what makes it scientific? In what ways does it differ from
	other forms of programming, if at all? Is scientific programming,
	data science or machine learning fundamentally different to
	constructing a compiler or building a high-throughput web server?
	By considering how the scientific method (with its falsifiable
	hypotheses and repeatable and reproducible experiments) relates to
	scientific programming, I hope to explore how computer science and
	traditional programming techniques are coming up short in meeting
	the requirements of scientific programmers.
</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" expanded="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/ferris2025hazel_of_ocaml/</fr:uri>
                        <fr:display-uri>ferris2025hazel_of_ocaml</fr:display-uri>
                        <fr:route>/ferris2025hazel_of_ocaml/</fr:route>
                        <fr:title text="Generating a corpus of Hazel programs from ill-typed OCaml programs">Generating a corpus of Hazel programs from ill-typed OCaml programs</fr:title>
                        <fr:taxon>Reference</fr:taxon>
                        <fr:meta name="external">https://patrick.sirref.org/var/tyde2025.pdf</fr:meta>
                        <fr:meta name="doi" />
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <fr:tree show-metadata="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                            </fr:date>
                            <fr:title text="Abstract">Abstract</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>
		When developing a new programming language, having a large corpus of
		both correct and incorrect programs allows language designers to test
		and explore the capabilities of their new language. However,
		bootstrapping such a corpus of incorrect programs is time-consuming and
		arduous. We therefore explore how to reuse code from more mature
		languages to generate a corpus of ill-typed code for newer ones. We
		have developed a compiler to Hazel, an emerging language with typed
		holes, from the more mature OCaml ecosystem. We find it practical to
		generate a comprehensive corpus of ill-typed programs for Hazel
		development, and discuss future larger scale efforts towards bridging
		ecosystems.
</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <html:p>See also <fr:link href="https://patricoferris.github.io/hazel_of_ocaml/" type="external">the online hazel of ocaml compiler</fr:link></html:p>
                    <fr:tree show-metadata="false" expanded="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Max Carroll/" type="external">Max Carroll</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/carroll2025decomposable_type_highlighting/</fr:uri>
                        <fr:display-uri>carroll2025decomposable_type_highlighting</fr:display-uri>
                        <fr:route>/carroll2025decomposable_type_highlighting/</fr:route>
                        <fr:title text="Decomposable Type Highlighting for Bidirectional Type and Cast Systems">Decomposable Type Highlighting for Bidirectional Type and Cast Systems</fr:title>
                        <fr:taxon>Reference</fr:taxon>
                        <fr:meta name="external">https://maxcarroll0.github.io/papers/workshops/HATRA-decomposable-type-highlighting/</fr:meta>
                        <fr:meta name="doi" />
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <fr:tree show-metadata="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Max Carroll/" type="external">Max Carroll</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                            </fr:date>
                            <fr:title text="Abstract">Abstract</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>
		 We explore how to provide programmers with an interactive
		 interface for explaining the process by which static types and
		 dynamic casts are derived, with the goal of improving the
		 debugging of static and dynamic type errors. To this end, we
		 define mathematical foundations for a decomposable highlighting
		 system within a bidirectional system, and show how these can be
		 propagated through dynamic types in a cast system. Our prototype
		 implementation in the gradually typed Hazel language includes a
		 web-based user interface, through which we highlight the
		 importance of type level debugging.
</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" expanded="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Michael Winston Dales/" type="external">Michael Winston Dales</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Alison Eyres/" type="external">Alison Eyres</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Francesca A. Ridley" type="external">Francesca A. Ridley</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Simon Tarr/" type="external">Simon Tarr</fr:link>
                          </fr:author>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                        </fr:date>
                        <fr:uri>https://patrick.sirref.org/dales2025yirgacheffe/</fr:uri>
                        <fr:display-uri>dales2025yirgacheffe</fr:display-uri>
                        <fr:route>/dales2025yirgacheffe/</fr:route>
                        <fr:title text="Yirgacheffe: A Declarative Approach to Geospatial Data">Yirgacheffe: A Declarative Approach to Geospatial Data</fr:title>
                        <fr:taxon>Reference</fr:taxon>
                        <fr:meta name="external">https://dl.acm.org/doi/10.1145/3759536.3763806</fr:meta>
                        <fr:meta name="doi">10.1145/3759536.3763806</fr:meta>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <fr:tree show-metadata="false">
                          <fr:frontmatter>
                            <fr:authors>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Michael Winston Dales/" type="external">Michael Winston Dales</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Alison Eyres/" type="external">Alison Eyres</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Francesca A. Ridley" type="external">Francesca A. Ridley</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Simon Tarr/" type="external">Simon Tarr</fr:link>
                              </fr:author>
                              <fr:author>
                                <fr:link href="https://patrick.sirref.org/Anil Madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>
                              </fr:author>
                            </fr:authors>
                            <fr:date>
                              <fr:year>2025</fr:year>
                            </fr:date>
                            <fr:title text="Abstract">Abstract</fr:title>
                          </fr:frontmatter>
                          <fr:mainmatter>
                            <html:p>
		We present Yirgacheffe, a declarative geospatial library that
		allows spatial algorithms to be implemented concisely, supports
		parallel execution, and avoids common errors by automatically
		handling data (large geospatial rasters) and resources (cores,
		memory, GPUs). Our primary user domain comprises ecologists,
		where a typical problem involves cleaning messy occurrence data,
		overlaying it over tiled rasters, combining layers, and deriving
		actionable insights from the results. We describe the successes
		of this approach towards driving key pipelines related to global
		biodiversity and describe the capability gaps that remain, hoping
		to motivate more research into geospatial domain-specific
		languages.
	</html:p>
                          </fr:mainmatter>
                        </fr:tree>
                      </fr:mainmatter>
                    </fr:tree>
                    <html:hr />
                    <html:p>I had some great conversations with <fr:link href="/kc/" title="KC Sivaramakrishnan" uri="https://patrick.sirref.org/kc/" display-uri="kc" type="local">KC</fr:link> too with respect to my current research.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2026</fr:year>
                  <fr:month>2</fr:month>
                  <fr:day>9</fr:day>
                </fr:date>
                <fr:title text="Future Work">Future Work</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>As I enter my final year of the PhD, my goal would be to try and align more of my fellowship work with my own research wherever it makes sense. This research focuses on the following hypothesis:</html:p>
                <html:blockquote>
                  <html:p>Embedding deep provenance tracking, reversible execution and mergeable histories directly into an interactive programming environment (a POSIX-like shell) greatly decreases the gap between exploratory scientific work and reproducible, publishable results; all whilst leaving existing workflows intact and being programming language agnostic.</html:p>
                </html:blockquote>
                <html:p>I want to focus on building these tools using <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>, <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> etc. There are other projects I wish to continue regardless, like <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link>, though just as a coordinator (not a mentor).</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Overlapping PhD Work">Overlapping PhD Work</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>There are multiple projects that overlap with my work. For example, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, which I wrote a <fr:link href="/irmin-retro/" title="Irmin Retrospective" uri="https://patrick.sirref.org/irmin-retro/" display-uri="irmin-retro" type="local">retrospective</fr:link> for. This is at the core of <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> and suggests an extremely valid use case for a brancheable, mergeable database.</html:p>
                    <html:p>In addition to this, continuing to work on <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> makes sense to me too. <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> currently has no maintainer and no active development, but the <fr:link href="https://github.com/ocaml-multicore/eio/issues" type="external">issues are piling up</fr:link>. In particular, I am making heavy use of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> in <fr:link href="/merry/" title="Merry" uri="https://patrick.sirref.org/merry/" display-uri="merry" type="local">Merry</fr:link>, a POSIX(ish) shell written in OCaml. Aside from research angles on brancheable and mergeable shells, I am also quite interested in how this might look in terms of OxCaml. I met with <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link> and <fr:link href="/talex5/" title="Thomas Leonard" uri="https://patrick.sirref.org/talex5/" display-uri="talex5" type="local">Thomas</fr:link> recently to discuss the future of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> and there was some agreement that we are all heavy users of it and hope to keep up its maintenance and set of features.</html:p>
                    <html:p>One large piece of work that is sorely needed here is moving <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> to <html:code>bytes</html:code> and not bigarray-backed <html:code>Cstruct</html:code>s. Any libraries using <html:code>bytesrw</html:code> (e.g. <html:code>jsont</html:code>) incur an extra copy of data into and out of the bytes. <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link> has been <fr:link href="https://anil.recoil.org/notes/oxcaml-httpz" type="external">working on some of the pieces</fr:link> recently to make this better!</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Maintaining and Releasing my own libraries">Maintaining and Releasing my own libraries</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I have published quite a few OCaml libraries in my time, below is just a few libraries (filtered to not include OCurrent projects).</html:p>
                    <html:pre><![CDATA[$ opam list --all --no-switch --columns=name,authors: | grep -E "sirref|Ferris" | cut -d " " -f1
carbon
geojson
geojsone
graft
hilite
ISO3166
jekyll-format
ppx_deriving_ezjsonm
ppx_deriving_yaml
rtree
search
topojson
topojsone
cid
multibase
multicodec
multihash
multihash-digestif]]></html:pre>
                    <html:p>Some of these are used in the community including <html:code>hilite</html:code>, <html:code>ppx_deriving_yaml</html:code> and the multi-codecs. I would like to do some general maintenance of some of these tools and release a few iterations of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> which now makes use of <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">bib</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Ppxlib Maintenance">Ppxlib Maintenance</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>By far, maintenance of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> takes up a majority of my time. I think, given the other work I need to focus on, it would be great to try to minimise the amount of time working on <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. In particular, perhaps only maintaining <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> as far as OCaml release-readiness is a possibility and important bug fixes (like <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/613" type="external">the OOM bug reported by Jane Street</fr:link>).</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2026</fr:year>
                      <fr:month>2</fr:month>
                      <fr:day>9</fr:day>
                    </fr:date>
                    <fr:title text="Forester, Graft and Writing">Forester, Graft and Writing</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>With all of this work, I am eager to communicate what I am up to and my thoughts on open source, OCaml, OxCaml etc. I am glad to be using <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> to do this, particularly as it is written in OCaml (and could make great use of my own work on <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>).</html:p>
                    <html:p>I hope to continue working on <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> and related tools like <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">bib</fr:link>. But I would also like to start writing some long-form content similar to the <fr:link href="/irmin-retro/" title="Irmin Retrospective" uri="https://patrick.sirref.org/irmin-retro/" display-uri="irmin-retro" type="local">Irmin retrospective</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>11</fr:month>
              <fr:day>15</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-w46/</fr:uri>
            <fr:display-uri>weekly-2025-w46</fr:display-uri>
            <fr:route>/weekly-2025-w46/</fr:route>
            <fr:title text="Shelter imports">Shelter imports</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Most of this week was spent fixing bugs in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> in an attempt to get it ready to run the <fr:link href="https://github.com/quantifyearth/LIFE" type="external">LIFE</fr:link> pipeline.</html:p>
            <html:p>To do so, <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> requires a mechanism by which to pull in files from the outside world. That could be configuration files, source trees, data etc. For now, this has taken the form of a crude <html:code>@ import</html:code> statement. In true <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> fashion, I have transcluded the <html:em>foreign</html:em> tree from my <fr:link href="https://shelter.sirref.org/logs" type="external">Shelter logs</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">https://shelter.sirref.org/Shelter Programmers/</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>16</fr:day>
                </fr:date>
                <fr:uri>https://shelter.sirref.org/shelter-log-001/</fr:uri>
                <fr:display-uri>https://shelter.sirref.org/shelter-log-001/</fr:display-uri>
                <fr:route>https://shelter.sirref.org/shelter-log-001/</fr:route>
                <fr:title text="Import statements">Import statements</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Welcome to the first <fr:link href="https://shelter.sirref.org/index/" type="external">Shelter</fr:link> log! In this log I will explain the work I have been doing to add an <html:code>@ import</html:code> <fr:link href="https://shelter.sirref.org/shelter-0002/" type="external">meta-command</fr:link>.</html:p>
                <html:p>The syntax thus far is relatively straightforward.</html:p>
                <html:pre><![CDATA[@ import --name=<optional-name> <URI> <DST>]]></html:pre>
                <html:p>There are a few key principles underlying <html:code>@ import</html:code>.</html:p>
                <html:ol>
                  <html:li>
                    <html:p>It should be at least as expressive as Docker's <html:code>COPY ...</html:code> command.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>It should deal with a wider variety of import sources. In addition to local <![CDATA[file paths this could be data over HTTP (]]> <html:code>https://</html:code><![CDATA[), git repositories, zip]]>  archives over ssh etc.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Imports, where possible, should be catalogued and shared across <fr:link href="https://shelter.sirref.org/at-session/" type="external">sessions</fr:link>.</html:p>
                  </html:li>
                </html:ol>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">https://shelter.sirref.org/Shelter Programmers/</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>16</fr:day>
                    </fr:date>
                    <fr:title text="URIs as Sources">URIs as Sources</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[Point (1) can be dealt with by point (2). Indeed, that latest development]]>  branch already allows users to import local files and directories into their session. For example:</html:p>
                    <html:pre><![CDATA[@ import shelter.opam .
opam install . --deps-only --with-test]]></html:pre>
                    <html:p>By allowing arbitrary URIs in the import command, we hope to force users away from downloading data via <html:code>curl</html:code> or python scripts. Lifting these side-effectful imports into <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> allows us to manage the data in a much cleaner fashion.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">https://shelter.sirref.org/Shelter Programmers/</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>16</fr:day>
                    </fr:date>
                    <fr:title text="Scripts as Sources">Scripts as Sources</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>One idea I had was to allow users to invoke scripts as there "import source". Something like:</html:p>
                    <html:pre><![CDATA[@ import -- python download_gedi_data.py]]></html:pre>
                    <html:p>And using the same <fr:link href="https://shelter.sirref.org/shelter-tracing/" type="external">eBPF tracing</fr:link> we use during normal execution we can capture a fairly good idea of the tools and files needed to perform an import.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://shelter.sirref.org/Shelter Programmers/" type="external">https://shelter.sirref.org/Shelter Programmers/</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>11</fr:month>
                      <fr:day>16</fr:day>
                    </fr:date>
                    <fr:title text="Sharing Imports">Sharing Imports</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>One example of better data management is that <fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> imports can be <![CDATA[explicitly shared across sessions via the naming mechanism (also by hash).]]></html:p>
                    <html:p>When a user imports some data, they can optionally name that piece of data. For example:</html:p>
                    <html:pre><![CDATA[@ import
  --name=belfast-trees \
  https://www.belfastcity.gov.uk/getmedia/262a1f01-f219-4780-835e-7a833bdd1e1c/odTrees.csv \
  /home]]></html:pre>
                    <html:p><fr:link href="https://shelter.sirref.org/shelter/" type="external">Shelter</fr:link> stores that away and makes a link between the name, the URI and the underlying data. A user may then import the same piece of data into a different session by simply writing:</html:p>
                    <html:pre><![CDATA[@ import --name=belfast-trees /var/lib]]></html:pre>
                    <html:p><![CDATA[The same data is shared (read-only) into this session. By asking for the user's]]>  intent via the naming scheme, it makes it possible to then <html:em>version</html:em> the data and have a means by which to update said data, one could imagine:</html:p>
                    <html:pre><![CDATA[@ update --name=belfast-trees]]></html:pre>
                    <html:p>Which will retry the original URI and see if the data has changed, or if it has not. There is an implicit versioning number that users can specify in the name should they choose to.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>15</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/eio-cap-debugging/</fr:uri>
                <fr:display-uri>eio-cap-debugging</fr:display-uri>
                <fr:route>/eio-cap-debugging/</fr:route>
                <fr:title text="Eio Debugging ">Eio Debugging </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>One of the promises of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>'s capability model is an improved debugging experience. Your program must be designed in such a way as to make resources explicit. If you have a <html:code>load_config</html:code> function, more than likely it will need access to the file-system.</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="ocaml-keyword-other">val</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">load_config</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language">_</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Path</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Config</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-comment-doc"><![CDATA[(**]]></html:span>
                    <html:span class="ocaml-comment-doc"><![CDATA[ [load_config path] loads a configuration from [path].]]></html:span>
                    <html:span class="ocaml-comment-doc"><![CDATA[*)]]></html:span>
                    <html:span class="ocaml-source">
</html:span>
                  </html:code>
                </html:pre>
                <html:p>Once all of your resources are explicit and threaded through your program, it becomes much easier to swap out one resource for another (provided they have the same interface).</html:p>
                <html:p>This week I was trying to get the <fr:link href="https://github.com/quantifyearth/LIFE" type="external">LIFE</fr:link> pipeline running in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link>. Part of that involves pulling the <fr:link href="ghcr.io/osgeo/gdal:ubuntu-small-3.11.4" type="external">appropriate geospatial container image</fr:link>, but my code was terrifically broken, failing with what looked to me with a Docker error.</html:p>
                <html:p>With only this clue, I knew that it was probably in the execution of some command in a child process, but which one? To trace this quickly, I could plug in a slightly different instance of the <html:code>_ Eio.Process.mgr</html:code> capability. Essentially unchanged from the one provided by the unix backend except that it would also print to stderr the command it was trying to run!</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">debug_process_mgr</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source">mgr</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">mgr</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">mgr</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">    </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword">module</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">D</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">struct</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">    </html:span>
                    <html:span class="ocaml-keyword-other">type</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-support-type">unit</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">    </html:span>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">spawn_unix</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-unit"><![CDATA[()]]></html:span>
                    <html:span class="ocaml-source"> ~</html:span>
                    <html:span class="ocaml-source">sw</html:span>
                    <html:span class="ocaml-source"> ?</html:span>
                    <html:span class="ocaml-source">cwd</html:span>
                    <html:span class="ocaml-source"> ?</html:span>
                    <html:span class="ocaml-source">pgid</html:span>
                    <html:span class="ocaml-source"> ?</html:span>
                    <html:span class="ocaml-source">uid</html:span>
                    <html:span class="ocaml-source"> ?</html:span>
                    <html:span class="ocaml-source">gid</html:span>
                    <html:span class="ocaml-source"> ~</html:span>
                    <html:span class="ocaml-source">env</html:span>
                    <html:span class="ocaml-source"> ~</html:span>
                    <html:span class="ocaml-source">fds</html:span>
                    <html:span class="ocaml-source"> ~</html:span>
                    <html:span class="ocaml-source">executable</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">args</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">      </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">traceln</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-string-quoted-double">"</html:span>
                    <html:span class="ocaml-string-quoted-double">Spawning subprocess... </html:span>
                    <html:span class="ocaml-constant-character-printf"><![CDATA[%a]]></html:span>
                    <html:span class="ocaml-string-quoted-double">"</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Fmt</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source">list</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-support-type">string</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">args</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">      </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">spawn_unix</html:span>
                    <html:span class="ocaml-source"> ~</html:span>
                    <html:span class="ocaml-source">sw</html:span>
                    <html:span class="ocaml-source"> ?</html:span>
                    <html:span class="ocaml-source">cwd</html:span>
                    <html:span class="ocaml-source"> ?</html:span>
                    <html:span class="ocaml-source">pgid</html:span>
                    <html:span class="ocaml-source"> ?</html:span>
                    <html:span class="ocaml-source">uid</html:span>
                    <html:span class="ocaml-source"> ?</html:span>
                    <html:span class="ocaml-source">gid</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">mgr</html:span>
                    <html:span class="ocaml-source"> ~</html:span>
                    <html:span class="ocaml-source">env</html:span>
                    <html:span class="ocaml-source"> ~</html:span>
                    <html:span class="ocaml-source">fds</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">        ~</html:span>
                    <html:span class="ocaml-source">executable</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">args</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword-other">end</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">in</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword">module</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">V</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Make_mgr</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">D</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">in</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Resource</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">T</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-constant-language-unit"><![CDATA[()]]></html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Pi</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">mgr_unix</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-keyword-other">module</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">V</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source">
</html:span>
                  </html:code>
                </html:pre>
                <html:p>Whist there is a fair amount of jumping through first-class-module-shaped hoops here, all I am doing is rewrapping an existing "method" to a spawn a unix child process. Then using <fr:link href="https://github.com/ocaml-multicore/eio/pull/823" type="external">this helper function</fr:link>, I can push that into my <fr:link href="https://patrick.sirref.org/standard environment/" type="external">standard environment</fr:link>.</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">env</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Stdenv</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">with_env</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  ~</html:span>
                    <html:span class="ocaml-source">process_mgr</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source">debug_process_mgr</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">env</html:span>
                    <html:span class="ocaml-keyword-other">#</html:span>
                    <html:span class="ocaml-source">process_mgr</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-source">env</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword-other">in</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Shelter</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">main</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">config</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source">env</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-keyword-operator">&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language">_</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Shelter</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">env</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">dir</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">cmd_file</html:span>
                    <html:span class="ocaml-source">
</html:span>
                  </html:code>
                </html:pre>
                <html:p>And sure enough I was querying for the Docker user <html:em>before</html:em> pulling the image! I hadn't run into this, as for the last while I have been using <html:code>alpine</html:code> and <html:code>debian</html:code> images that already exists locally.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>11</fr:month>
              <fr:day>10</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-w45/</fr:uri>
            <fr:display-uri>weekly-2025-w45</fr:display-uri>
            <fr:route>/weekly-2025-w45/</fr:route>
            <fr:title text="Taking stock &amp; Graft updates">Taking stock &amp; Graft updates</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>I ended up working on a real mix of things last week. I managed to get two large posts uploaded to this site: an <fr:link href="/icfp-2025/" title="ICFP 2025" uri="https://patrick.sirref.org/icfp-2025/" display-uri="icfp-2025" type="local">ICFP recap</fr:link> and a deeper-dive into the random bits of <fr:link href="/ocaml-roundup-october-2025/" title="OCaml Roundup: October 2025" uri="https://patrick.sirref.org/ocaml-roundup-october-2025/" display-uri="ocaml-roundup-october-2025" type="local">OCaml hacking</fr:link>. This was pretty useful in terms of taking stock of where I was at, I always find post-conference, I'm a little lost. The conversations and ideas from ICFP are simultaneously exciting but also pretty inactionable.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/graft-updates/</fr:uri>
                <fr:display-uri>graft-updates</fr:display-uri>
                <fr:route>/graft-updates/</fr:route>
                <fr:title text="Graft Updates ">Graft Updates </fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>It would seem that there is a potential <html:em>second</html:em> user of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link>! A great source of motivation for some tidying and feature implementing. At the end of last week I fixed some little bugs in <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> and (more importantly) allowed <fr:link href="https://graft.sirref.org/named-subtrees" type="external">users to name their subtrees</fr:link>. Upstream <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link> also now pins and uses my <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">Bibtex implementation</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="OCaml Geotessera">OCaml Geotessera</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>As I discussed in my <fr:link href="/ocaml-roundup-october-2025/" title="OCaml Roundup: October 2025" uri="https://patrick.sirref.org/ocaml-roundup-october-2025/" display-uri="ocaml-roundup-october-2025" type="local">OCaml roundup</fr:link>, I spent a bit of time polishing the <fr:link href="https://tangled.org/@patrick.sirref.org/ocaml-geotessera" type="external">OCaml geotessera code</fr:link>. In particular this meant starting to handle low-level geospatial transformations allowing users to project latitudes and longitudes into the rows and columns of their raster data. I feel like I'm stumbling onto a path <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> has carved out with <fr:link href="https://github.com/quantifyearth/yirgacheffe/" type="external">Yirgacheffe</fr:link>. I'm following <fr:link href="https://digitalflapjack.com/weeknotes/2025-11-10/" type="external">along with his work excitedly</fr:link> and we had a good catch-up last week discussing how libraries should handle things like automatic, numeric precision conversion.</html:p>
                <html:p>As a fully paid-up member of the static types fan club, I'm often evangelising the benefits of types. However, I hit a little quirk of the <fr:link href="https://ocaml.org/p/nx" type="external">Nx</fr:link> library in OCaml (a numpy equivalent). Take a look at this sum function:</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">sum</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">nx</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">sum</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">nx</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">|&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">item</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-list"><![CDATA[[]]]></html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword-other">val</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">sum</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-storage-type">'b</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-entity-name-function-binding">arr</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">create</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">int8</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[[|]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">2</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[|]]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[[|]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">64</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">64</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[|]]]></html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword-other">val</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">arr</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-support-type">int</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Bigarray</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">int8_signed_elt</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Nx</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">sum</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">arr</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword-operator">-</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-support-type">int</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-</html:span>
                    <html:span class="ocaml-constant-numeric-decimal-integer">128</html:span>
                    <html:span class="ocaml-source">
</html:span>
                  </html:code>
                </html:pre>
                <html:p>Even though <html:code>sum</html:code> takes an <html:code>('a, 'b) Nx.t</html:code> array that stores elements with representation <html:code>'b</html:code> and allows you to read/write to the elements with OCaml values of type <html:code>'a</html:code>, the <html:code>sum</html:code> function performs the calculation in the world of the <html:code>'b</html:code> representation type (here signed 8-bit integers). So we get an overflow! Perhaps not too surprising but easy to overlook! The moral of the story is that we still need to be careful in the OCaml world too.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="Shelter">Shelter</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I did a little cleaning up of the <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> code too. I noticed a few bugs from the demos I did at <fr:link href="/icfp-2025/" title="ICFP 2025" uri="https://patrick.sirref.org/icfp-2025/" display-uri="icfp-2025" type="local">ICFP</fr:link>. Most were pretty straight-forward to fix, and the test-suite is now checking <fr:link href="https://github.com/fn06/shelter/blob/main/test/fixtures/for.shl" type="external">parallel for-loops</fr:link> and <fr:link href="https://github.com/fn06/shelter/blob/main/test/fixtures/if.shl" type="external">conditional execution</fr:link> are working.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>11</fr:month>
                  <fr:day>10</fr:day>
                </fr:date>
                <fr:title text="This week">This week</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I hope to get a few things done this week:</html:p>
                <html:ul>
                  <html:li>
                    <html:p>Run some part of the <fr:link href="https://github.com/quantifyearth/LIFE" type="external">LIFE</fr:link> pipeline through <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Deploy the <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> daemon allowing other people to connect and take it for a spin.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Spend some time writing and reading, pulling ideas together rather than always writing code!</html:p>
                  </html:li>
                  <html:li>
                    <html:p>I have a slightly harebrained scheme that combines <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>, atproto, <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link>, capn(proto/web) and webcomponents... I want to see if I can pull that together.</html:p>
                  </html:li>
                </html:ul>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>10</fr:month>
              <fr:day>24</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/icfp-2025/</fr:uri>
            <fr:display-uri>icfp-2025</fr:display-uri>
            <fr:route>/icfp-2025/</fr:route>
            <fr:title text="ICFP 2025">ICFP 2025</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Two weeks ago I was fortunate enough to attend the <fr:link href="https://icfp25.sigplan.org/" type="external">International Conference on Functional Programming</fr:link> in Singapore. My first time in Asia and my second time at the conference, what follows are some thoughts and presentations I enjoyed whilst I was there.</html:p>
            <html:p>I must thank my office mate (and friend!) <fr:link href="https://ryan.freumh.org/" type="external">Ryan Gibb</fr:link> for his camaraderie and sage advice: "the best track is <html:em>hallway</html:em> track". Not to mention all of his <fr:link href="https://ryan.freumh.org/photos.html" type="external">photos</fr:link> too. Thanks Ryan!</html:p>
            <html:div style="text-align: center">
  <html:img class="inner-img" src="/bafkrmid2d6u3qdufa6m5gogavtwm6uqksaicozrc5s2unrtzjtth3hpvey.jpeg" alt="Description follows image." />
</html:div>
            <html:p>From right to left, top to bottom: <fr:link href="https://patrick.sirref.org/anil madhavapeddy/" type="external">Anil Madhavapeddy</fr:link>, <fr:link href="https://patrick.sirref.org/sadiq jaffer/" type="external">Sadiq Jaffer</fr:link>, <fr:link href="https://patrick.sirref.org/patrick ferris/" type="external">Patrick Ferris</fr:link>, <fr:link href="https://patrick.sirref.org/ryan gibb/" type="external">Ryan Gibb</fr:link> and <fr:link href="https://patrick.sirref.org/roy ang/" type="external">Roy Ang</fr:link>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>10</fr:month>
                  <fr:day>24</fr:day>
                </fr:date>
                <fr:title text="Random Hacking">Random Hacking</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Below are just some of the pieces of random hacking I got up to whilst in Singapore.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:uri>https://patrick.sirref.org/oxcaml-and-uring/</fr:uri>
                    <fr:display-uri>oxcaml-and-uring</fr:display-uri>
                    <fr:route>/oxcaml-and-uring/</fr:route>
                    <fr:title text="OxCaml and Uring">OxCaml and Uring</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Jane Street were a big presence at ICFP 2025, carting along with them a shiny new OCaml compiler: <fr:link href="https://oxcaml.org/" type="external">OxCaml</fr:link>. If have been <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">playing around with OxCaml recently</fr:link> but nothing outside toplevels in Javascript. Until now!</html:p>
                    <html:p>After talking to <fr:link href="/dra27/" title="David Allsopp" uri="https://patrick.sirref.org/dra27/" display-uri="dra27" type="local">David</fr:link>, I spent some time converting a small corner of the <fr:link href="https://github.com/ocaml-multicore/ocaml-uring" type="external">ocaml-uring</fr:link> library to use a part of <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link>. In particular making the following change:</html:p>
                    <html:pre class="hilite">
                      <html:code>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword-other">module</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">Heap</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other">struct</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword-other">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">ptr</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-support-type">int32</html:span>
                        <html:span class="ocaml-keyword-other">#</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-comment-block"><![CDATA[(*]]></html:span>
                        <html:span class="ocaml-comment-block"> ... </html:span>
                        <html:span class="ocaml-comment-block"><![CDATA[*)]]></html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword-other">end</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword-other">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">cqe</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source"><![CDATA[{]]></html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-source">user_data_id</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">Heap</html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                        <html:span class="ocaml-source">ptr</html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-source">res</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-support-type">int32</html:span>
                        <html:span class="ocaml-keyword-other">#</html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-source"><![CDATA[}]]></html:span>
                        <html:span class="ocaml-source">
</html:span>
                      </html:code>
                    </html:pre>
                    <html:p>The idea being that a completion queue entry (a notification that some operation has completed) could be fully represented using 64 bits (two 32-bit, <fr:link href="https://oxcaml.org/documentation/unboxed-types/01-intro/" type="external">unboxed values</fr:link>). You can <fr:link href="https://github.com/ocaml-multicore/ocaml-uring/compare/main...patricoferris:ocaml-uring:oxcaml?expand=1" type="external">see how this impacted the library</fr:link>! I'm not certain about this change (and I'm sure I did it wrong) but it was nice to realise <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> gives you this kind of control. However, I am worried about the ergonomics of manipulating values like <html:code>int32#</html:code> and the temptation to case it into an <html:code>int</html:code> (presumably losing a good portion of the value of having an unboxed value in the first place).</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>10</fr:month>
                      <fr:day>24</fr:day>
                    </fr:date>
                    <fr:title text="Bibtex Parser">Bibtex Parser</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>On the flight over to Singapore, I started to write a post for this website. Some readers may remember that I use <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">forester</fr:link> after a preprocessing step via <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> to build this site. Part of that preprocessing consumes bibtex files and outputs forester trees. For the initial <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> release I used the excellent <fr:link href="https://github.com/Octachron/talaria_bibtex" type="external">Talaria Bibtex</fr:link> library. Unfortunately, it presented a pretty confusing API that, whilst nicely typed, felt a little cumbersome to use. Additionally, it was too specific in what it would accept as valid Bibtex. I wanted something that was a little more straight-forward to use (if a little fast-and-loose when it comes to types...). And so I built <fr:link href="/bib/" title="Bib" uri="https://patrick.sirref.org/bib/" display-uri="bib" type="local">bib</fr:link>.</html:p>
                    <html:p>This was my first real attempt at using the <fr:link href="https://ocaml.org/p/bytesrw" type="external">Bytesrw</fr:link> library. I was happy with the results, although I did have to copy a substantial amount of code from <fr:link href="https://ocaml.org/p/jsont" type="external">other bytesrw-compatible libraries</fr:link>. I'd be happy to shift to this <html:code>bytes</html:code>-first world if it wasn't for the ever-present-in-my-mind issue of relocatable values in the OCaml heap!</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>10</fr:month>
                      <fr:day>24</fr:day>
                    </fr:date>
                    <fr:title text="Geocaml Libraries">Geocaml Libraries</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>There has been some excellent <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">outreachy</fr:link> work happening on the <fr:link href="https://github.com/geocaml/ocaml-tiff" type="external">geocaml/ocaml-tiff</fr:link> library which is a potential Outreachy internship project for December 2025. More on this in a future post.</html:p>
                    <html:p>On the way back (and a little during the conference), I spent some time building an OCaml counterpart to <fr:link href="https://github.com/ucam-eo/geotessera/" type="external">geotessera</fr:link>, a library for working with <fr:link href="/tessera2025/" title="TESSERA: Temporal Embeddings of Surface Spectra for Earth Representation and Analysis" uri="https://patrick.sirref.org/tessera2025/" display-uri="tessera2025" type="local">Tessera</fr:link>. The library is not ready for people to use directly, but I was working on various constituent parts including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p><fr:link href="https://github.com/geocaml/ocaml-proj" type="external">Modern OCaml bindings to PROJ</fr:link> (a coordinate reference system projection library)</html:p>
                      </html:li>
                      <html:li>
                        <html:p>
                          <fr:link href="https://github.com/geocaml/ocaml-wkt" type="external">Further work on a WKT library for OCaml</fr:link>
                        </html:p>
                      </html:li>
                      <html:li>
                        <html:p>Coming soon... ocaml-geotessera</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>10</fr:month>
                  <fr:day>24</fr:day>
                </fr:date>
                <fr:title text="Talks">Talks</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>10</fr:month>
                      <fr:day>24</fr:day>
                    </fr:date>
                    <fr:title text="Hazel of OCaml at TyDe">Hazel of OCaml at TyDe</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The <html:em>type-driven development</html:em> (TyDe) workshop was held on the first day of ICFP at the <fr:link href="https://www.comp.nus.edu.sg/" type="external">NUS School of Computing</fr:link>. I find the workshop name to be a little misleading, but perhaps this comes from my engineering background. The talks focused a lot on type <html:em>theory</html:em>, presenting the formal mathematics of interesting type systems with less focus on <html:em>why</html:em> it might be useful to have such an exotic type system... but then again, that was the nature of the entire conference.</html:p>
                    <html:p>I presented a talk on <fr:link href="/hazel-of-ocaml/" title="A Transpiler from OCaml to Hazel" uri="https://patrick.sirref.org/hazel-of-ocaml/" display-uri="hazel-of-ocaml" type="local">hazel_of_ocaml</fr:link>. The <fr:link href="https://patrick.sirref.org/var/tyde2025.pdf" type="external">slides are here</fr:link>, along with the <fr:link href="https://patrick.sirref.org/var/tyde2025-ea.pdf" type="external">extended abstract</fr:link>. My talk ended up focusing a lot on the pedagogical benefits of having a type system that helped explain the most important thing a type system does... catch type errors! This work represents a small piece of work inside <fr:link href="https://maxcarroll0.github.io/" type="external">Max Carroll's</fr:link> excellent <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">part II</fr:link> project, which he presented at the <fr:link href="https://maxcarroll0.github.io/papers/workshops/HATRA-decomposable-type-highlighting/" type="external">HATRA workshop</fr:link>: <html:em>Decomposable Type Highlighting for Bidirectional Type and Cast Systems</html:em>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>10</fr:month>
                      <fr:day>24</fr:day>
                    </fr:date>
                    <fr:title text="Scientific Programming at PROPL">Scientific Programming at PROPL</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I think it is important to be honest whenever you get a talk accepted that you otherwise feel should not have been. My talk "<html:em>about scientific programming what we talk about when we talk</html:em>" is one such talk. The <fr:link href="https://patrick.sirref.org/var/propl2025.pdf" type="external">slides are here</fr:link>. The talk itself was nothing to write home about, but I think there were a few nice ideas that came out of it and the conversations I had with fellow PROPL attenders.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>10</fr:month>
                          <fr:day>24</fr:day>
                        </fr:date>
                        <fr:title text="TMF Data Discrepancies Redux">TMF Data Discrepancies Redux</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>On the eve of my talk, I decided to re-run some analysis I did a few years ago on the <fr:link href="https://forobs.jrc.ec.europa.eu/TMF/data#downloads" type="external">tropical moist forest dataset</fr:link>, knowing that since then a few more years had become available. After fighting with some bit-rot in the Google Earth Engine script I had used, the new results were not very uplifting.</html:p>
                        <html:table>
    <html:tbody>
    <html:tr>
    <html:td><html:strong>Land Use Class</html:strong></html:td>
    <html:td><html:strong>Percent Change</html:strong></html:td>
    </html:tr>
    <html:tr>
    <html:td>Undisturbed</html:td>
    <html:td> -2.9</html:td>
    </html:tr>
    <html:tr>
    <html:td>Degraded</html:td>
    <html:td> -5.5</html:td>
    </html:tr>
    <html:tr style="background: yellow">
    <html:td>Deforested</html:td>
    <html:td> 8.6</html:td>
    </html:tr>
    <html:tr>
    <html:td>Regrowth</html:td>
    <html:td> 0.5</html:td>
    </html:tr>
    <html:tr>
    <html:td>Water</html:td>
    <html:td> 0.0</html:td>
    </html:tr>
    <html:tr>
    <html:td>Other</html:td>
    <html:td>-0.6</html:td>
    </html:tr>
    </html:tbody>
</html:table>
                        <html:p>The data in the table corresponds to the land use class values in Indonesia in the year 2008. The analysis computed the difference across each of the classes between the dataset released in 2021 and the dataset released in 2024. Most notably, the amount of deforested land has gone up by <html:em>8.6</html:em> percent!</html:p>
                        <html:p>As a somewhat tangential, though related, aside, I had the pleasure of talking to <fr:link href="https://cs.nyu.edu/~shw8119/" type="external">Sam Westrick</fr:link>, <fr:link href="https://forthoney.github.io/" type="external">Seong-Heon Jung</fr:link> and <fr:link href="https://svishnus.github.io/" type="external">Sundara Vishnu Satish</fr:link> of the <fr:link href="https://nyu-parcour.github.io/" type="external">ParCour</fr:link> research group. They were telling me about <fr:link href="https://github.com/mpllang/mpl" type="external">MaPLe</fr:link>, a programming language from the MLs built for parallelism. We discussed some ideas of using real-world, geospatial algorithms as benchmarks for MaPLe. <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link>, if you got this far remind me to chat to you about this!</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>10</fr:month>
                          <fr:day>24</fr:day>
                        </fr:date>
                        <fr:title text="Shelter Reactions">Shelter Reactions</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>At the end of my talk, I briefly mentioned <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link>. By far, this was the topic I got the most engagement on post-talk. During the conference, this was also true when people asked what I was working on. The tag line "a shell with <html:em>undo</html:em>" seemed to capture the attention of most people.</html:p>
                        <html:p>I'm feeling a renewed sense of interest in my own work thanks to that, even if the "research" contributions are not very apparent. However, I also had a good discussion with <fr:link href="https://kcsrk.info/" type="external">KC</fr:link> about the underlying <fr:link href="https://patrick.sirref.org/mrdt/" type="external">MRDT</fr:link> in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> and how we might think about collaborating in the future on MRDT-related work.</html:p>
                        <html:p>Related to that, I managed to spend the evening in <fr:link href="https://www.openstreetmap.org/relation/18195609#map=16/1.28090/103.84222" type="external">Chinatown</fr:link> with <fr:link href="https://dynamicaspects.org/research/" type="external">Roly Perera</fr:link>. Roly's work has focused on <fr:link href="https://f.luid.org/" type="external">Fluid</fr:link>, a transparency-based programming language that allows authors to reveal their computation to their user. Excitingly, Roly presented a <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/propl-2025-papers/10/Authoring-Tools-for-Transparent-Climate-Reporting" type="external">new text-based part of the language</fr:link> at PROPL. Our work is in the same universe, loosely orbiting some notion of reproducibility and explainability, but quite different in engineering work and how users might actually interact with our systems. I thoroughly enjoyed talking about solutions or research ideas that <html:em>preserve</html:em> existing workflows. Roly was great at pulling that out of the current work I have been doing.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>10</fr:month>
                  <fr:day>24</fr:day>
                </fr:date>
                <fr:title text="Other Talks and Highlights">Other Talks and Highlights</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I was a part of, often in a very small way, some other talks that were presented at ICFP including</html:p>
                <html:ul>
                  <html:li>
                    <html:p><fr:link href="https://www.youtube.com/watch?v=j84ocjlj1JA&amp;amp;t=12880s" type="external">Functional Networking for Docker</fr:link>, I encourage you to read <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil's</fr:link> <fr:link href="https://anil.recoil.org/notes/icfp25-ocaml5-js-docker#functional-networking-at-docker" type="external">notes on the topic</fr:link>. It is also worth mentioning <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil's</fr:link> <fr:link href="https://anil.recoil.org/notes/icfp25-post-posix" type="external">post-posix talk</fr:link> (not unrelated to my Uring musings above).</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> gave an excellent, <html:em>very live</html:em>, talk about <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/propl-2025-papers/6/Yirgacheffe-a-declarative-approach-to-geospatial-data" type="external">Yirgacheffe</fr:link> at PROPL which I thoroughly enjoyed. I'm also excited about his recent developments which I'm sure you can clue into <fr:link href="https://digitalflapjack.com/weeknotes/" type="external">over on his blog</fr:link>.</html:p>
                  </html:li>
                </html:ul>
                <html:p>Below is a non-exhaustive list of talks I enjoyed whilst at the conference. Some relevant, most of them not!</html:p>
                <html:ul>
                  <html:li>
                    <html:p>By far, one of the best talks was <fr:link href="https://icfp25.sigplan.org/details/icfp-2025-papers/13/Polynomial-Time-Program-Equivalence-for-Machine-Knitting" type="external">Polynomial-time Program Equivalence for Machine Knitting</fr:link>. I think the talk really nailed the "here's the idea, the details are in the paper"-presenting style as they described an "...algorithm that canonicalizes the algebraic representations of the topological semantics of machine knitting programs".</html:p>
                  </html:li>
                  <html:li>
                    <html:p>I attended most of the <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/icfp-splash-2025-tutorials/5/A-guided-tour-through-Oxidized-OCaml" type="external">OxCaml tutorial</fr:link> presented by the incredibly friendly <fr:link href="https://gavinleroy.com/" type="external">Gavin Gray</fr:link>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="/ryangibb/" title="Ryan Gibb" uri="https://patrick.sirref.org/ryangibb/" display-uri="ryangibb" type="local">Ryan</fr:link>'s talk <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/propl-2025-papers/13/Spatial-Programming-for-Environmental-Monitoring" type="external">Spatial Programming for Environmental Monitoring</fr:link> at PROPL was excellent.</html:p>
                  </html:li>
                </html:ul>
                <html:p>There's plenty more to talk about, and I'm sure my future posts will reference other parts of my experience at ICFP 2025. Thanks for reading, and if anybody is interested in any aspects of this do reach out!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>9</fr:month>
              <fr:day>2</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-weekly-2025-w32-w35/</fr:uri>
            <fr:display-uri>ocaml-weekly-2025-w32-w35</fr:display-uri>
            <fr:route>/ocaml-weekly-2025-w32-w35/</fr:route>
            <fr:title text="OCaml Weekly 2025 w32 to w35">OCaml Weekly 2025 w32 to w35</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>I have been working on a few different OCaml-related projects over the last few weeks. This is also coinciding with my partner and I moving across the UK, which has made finding time to write <fr:link href="/weeklies/" title="Patrick Ferris' Weeklies" uri="https://patrick.sirref.org/weeklies/" display-uri="weeklies" type="local">weeklies</fr:link> and <fr:link href="/posts/" title="Posts" uri="https://patrick.sirref.org/posts/" display-uri="posts" type="local">posts</fr:link> a little tricky. Nevertheless, here are some of the things I have been thinking about and working on!</html:p>
            <html:p>I managed to publish one signficant post this month: a <fr:link href="/irmin-retro/" title="Irmin Retrospective" uri="https://patrick.sirref.org/irmin-retro/" display-uri="irmin-retro" type="local">retrospective on Irmin</fr:link>.</html:p>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>9</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Eio">Eio</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Increasingly, I'm feeling the dream of a unified framework for asynchronous IO slipping through the OCaml community's fingers. It is perhaps not such a bad thing, and I think with the right library authoring we can at least get to a place where it isn't so bad, for example <fr:link href="https://github.com/geocaml/ocaml-tiff/blob/0dd98659642d1d9741068bb1eb943b4edeb5b5d6/src/tiff.ml#L2" type="external">providing read functions</fr:link> as opposed to using an opinionated IO library directly.</html:p>
                <html:p>That being said, I am a very happy user of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> when those choices do not matter, as is the case in building your own application (e.g. <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>). To this end, I have spent a good bit of time upstreaming support for various missing pieces in Eio's API including:</html:p>
                <html:ul>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/803" type="external">Setuid and setgid</fr:link> fork action's for the process API.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/802" type="external">Set process group</fr:link> support for job control in the process API.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-multicore/eio/pull/796" type="external">Responding to <html:code>Buf_write.of_flow</html:code></fr:link> request, and tinkering with the example there. I think this does highlight the awkwardness of making code portable across concurrency mechanisms, particularly with Eio's structured concurrency.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>I did <fr:link href="https://github.com/ocaml-multicore/eio/issues/788#issuecomment-3224454812" type="external">some investigating into <html:code>EINTR</html:code> bug</fr:link> which seems to be stemming from a known-issue on Uring in that writes are not buffered which usually does not matter except perhaps when there are parallel writes to <html:code>stdout</html:code>.</html:p>
                  </html:li>
                  <html:li>
                    <html:p><fr:link href="https://github.com/ocaml-multicore/eio/issues/807" type="external">Spent some time thinking about the fiber local storage across domains issue</fr:link>, I've passed on some thoughts to folks working on this.</html:p>
                  </html:li>
                </html:ul>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>9</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Vpnkit">Vpnkit</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>You might recall <fr:link href="/vpnkit-upgrade/" title="Defunctorising VPNKit" uri="https://patrick.sirref.org/vpnkit-upgrade/" display-uri="vpnkit-upgrade" type="local">I was interested in using vpnkit</fr:link>. <fr:link href="https://hannes.robur.coop/" type="external">Hannes</fr:link> has done an amazing amount of work (patching and releasing) a series of packages to get this into a place that is much better and could be considered soon for merging. This defunctorisation is actually very useful for the Eio port I wrote a long time ago.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>9</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="Papers and Talks at ICFP">Papers and Talks at ICFP</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Somehow, I have ended up on lots of papers and talks at ICFP and the co-located events in October. The vaguely OCaml-related ones include:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Essentially a <fr:link href="https://icfp25.sigplan.org/details/icfp-2025-papers/21/Functional-Networking-for-Millions-of-Docker-Desktops-Experience-Report-" type="external">Vpnkit Experience Report</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>An extended abstract on generating a corpus of ill-typed Hazel programs was accepted into <fr:link href="https://conf.researchr.org/home/icfp-splash-2025/tyde-2025" type="external">TyDe workshop</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Relatedly, the work that project supported was accepted into HATRA which was the <fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">Part II project I supervised</fr:link>: <fr:link href="https://conf.researchr.org/details/icfp-splash-2025/hatra-2025-papers/2/Decomposable-Type-Highlighting-for-Bidirectional-Type-and-Cast-Systems" type="external">Decomposable Type Highlighting for Bidirectional Type and Cast Systems</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>And <fr:link href="https://conf.researchr.org/home/icfp-splash-2025/propl-2025" type="external">two PROPL talks</fr:link>!</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>9</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Outreachy">Outreachy</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>We have come to the end of another Outreachy round! I will write more on this soon in its own separate post. But for now I am very grateful to this round's mentors <fr:link href="https://www.gridbugs.org/" type="external">gridbugs</fr:link> and <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">mdales</fr:link>, and also our fantastic interns. If you are interested, please do watch our demo day presentations.</html:p>
                <html:div style="text-align: center">
    <html:iframe title="Outreachy May 2025 Demo Day" width="560" height="315" src="https://watch.ocaml.org/videos/embed/kZJRFM6iw9ug9BLNjEgKeH" frameborder="0" allowfullscreen="" sandbox="allow-same-origin allow-scripts allow-popups allow-forms" />
</html:div>
                <html:p>The next round is fast approaching and we still need to work out the logistics. But I had a good conversation with <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">mdales</fr:link> about possible <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link> projects that I intend to submit!</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>8</fr:month>
              <fr:day>7</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/irmin-retro/</fr:uri>
            <fr:display-uri>irmin-retro</fr:display-uri>
            <fr:route>/irmin-retro/</fr:route>
            <fr:title text="Irmin Retrospective">Irmin Retrospective</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> is an OCaml library for building <html:em>branchable</html:em> and <html:em>mergeable</html:em> data stores. The data is <html:em>mergeable</html:em> in the sense of <fr:link href="/kcrsk-mrdts-2022/" title="Certified mergeable replicated data types" uri="https://patrick.sirref.org/kcrsk-mrdts-2022/" display-uri="kcrsk-mrdts-2022" type="local">mergeable replicated data types</fr:link>.</html:p>
            <html:p>I have been using Irmin for over five years to build different kinds of interesting data stores including:</html:p>
            <html:ul>
              <html:li>
                <html:p>A <fr:link href="https://github.com/patricoferris/omditor" type="external">simple markdown-based note-taking web application</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>A <fr:link href="https://github.com/carboncredits/retirement-db" type="external">content-addressed database</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>Mentoring an intern who <fr:link href="https://tarides.com/blog/2022-08-02-irmin-in-the-browser/" type="external">worked on Irmin in the browser</fr:link>.</html:p>
              </html:li>
              <html:li>
                <html:p>Most recently, an <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Irmin-backed shell session manager</fr:link>.</html:p>
              </html:li>
            </html:ul>
            <html:p>I was asked to provide some feedback recently on <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, so I thought writing a little retrospective here would be a good way to do that. The remit for the retrospective was about improving <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, so the content is focussed on pain points and areas of improvement.</html:p>
            <html:pre class="hilite">
              <html:code>
                <html:span class="ocaml-comment-block"><![CDATA[(*]]></html:span>
                <html:span class="ocaml-comment-block"> An in-memory Irmin store </html:span>
                <html:span class="ocaml-comment-block"><![CDATA[*)]]></html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-keyword-other">module</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Store</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-operator">=</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Irmin_mem</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">KV</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Make</html:span>
                <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Contents</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">String</html:span>
                <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                <html:span class="ocaml-source">
</html:span>
              </html:code>
            </html:pre>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="What is Irmin?">What is Irmin?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>, at its simplest, is a key-value database. Users associate keys with values and can query and update these bindings.</html:p>
                <html:p>Additionally, this database supports versioning. This means independent snapshots of the database can coexist and users can switch between them and update them without fear of interfering with other versions.</html:p>
                <html:p>Different versions of the database can be combined by <html:em>merging</html:em>. When you set up your instance of an <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> database, you also provide it with a <fr:link href="/kcrsk-mrdts-2022/" title="Certified mergeable replicated data types" uri="https://patrick.sirref.org/kcrsk-mrdts-2022/" display-uri="kcrsk-mrdts-2022" type="local">merge function</fr:link>.</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="ocaml-mdx-hash">#</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">#</html:span>
                    <html:span class="ocaml-keyword-other">show_type</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span>
                    <html:span class="ocaml-source">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Merge</html:span>
                    <html:span class="ocaml-source">.</html:span>
                    <html:span class="ocaml-source">f</html:span>
                    <html:span class="ocaml-source">;;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword-other">type</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">nonrec</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">f</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">    </html:span>
                    <html:span class="ocaml-source">old</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Merge</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">promise</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">    </html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-storage-type">'a</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Irmin</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Merge</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">conflict</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">result</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source">
</html:span>
                  </html:code>
                </html:pre>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Design and API">Design and API</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>'s API is very git-inspired. There is a large overlap of shared vocabulary and concepts: <html:em>repositories</html:em>, <html:em>branches</html:em>, <html:em>commits</html:em>, <html:em>heads</html:em> etc.</html:p>
                <html:p>Probably the most confusing aspect of this is the notion of a <html:code>Store</html:code>. When I was describing <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> above, I used the term <html:em>database</html:em> to help distinguish between some of these concepts. In Irmin's documentation, it is used for multiple related (but different) concepts. In "<fr:link href="https://irmin.org/tutorial/getting-started/#creating-a-store" type="external">Creating a Store</fr:link>" stores refer to the entire database, whereas in the <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> API docs we have that:</html:p>
                <html:blockquote>
                  <html:p>There are two kinds of store in Irmin: the ones based on persistent named branches and the ones based temporary detached heads.</html:p>
                </html:blockquote>
                <html:p>For <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> library users, a <html:code>Store.t</html:code> can be thought of as a checkout of the database at a particular revision. This may be from a branch or a specific commit.</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="ocaml-mdx-hash">#</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Store</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">of_branch</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword-operator">-</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Store</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">repo</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-support-type">string</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Store</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">&lt;</html:span>
                    <html:span class="ocaml-keyword-other">fun</html:span>
                    <html:span class="ocaml-keyword-operator">&gt;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-mdx-hash">#</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Store</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">of_commit</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-keyword-operator">-</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Store</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">commit</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Store</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-capital-identifier">Lwt</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                    <html:span class="ocaml-source">t</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">&lt;</html:span>
                    <html:span class="ocaml-keyword-other">fun</html:span>
                    <html:span class="ocaml-keyword-operator">&gt;</html:span>
                    <html:span class="ocaml-source">
</html:span>
                  </html:code>
                </html:pre>
                <html:p>The overloading of the term is confusing. I think it leaves users unsure about what other people might mean when they say "store". Being careful with these terms, and the contexts in which they are used, would help avoid this confusion.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Module and Functor Soup">Module and Functor Soup</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Undoubtedly for a majority of use-cases and users, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> is over-functorised. Nearly every module requires that you must apply some functor to access any useful code. In general, a user will have to interact with the <fr:link href="https://mirage.github.io/irmin/irmin/Irmin/module-type-S/Schema/index.html" type="external"><html:code>Schema</html:code> module</fr:link> when describing the types they want to instantiate their store with.</html:p>
                    <html:p>To counteract this, Irmin has plenty of <html:code>KV</html:code> modules that provide a <html:code>Make</html:code> functor that only requires a user to provide a suitable <html:em>content</html:em> module for their store (i.e. something that provides a type, a runtime representation of that type and a merge function).</html:p>
                    <html:pre class="hilite">
                      <html:code>
                        <html:span class="ocaml-mdx-hash">#</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other">#</html:span>
                        <html:span class="ocaml-keyword-other">show_module</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">Irmin_mem</html:span>
                        <html:span class="ocaml-source">.</html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">KV</html:span>
                        <html:span class="ocaml-source">;;</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-keyword-other">module</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">KV</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword-other">sig</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">endpoint</html:span>
                        <html:span class="ocaml-source"> = unit
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">metadata</html:span>
                        <html:span class="ocaml-source"> = unit
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">hash</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">info</html:span>
                        <html:span class="ocaml-source"> = Store.info
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source"><![CDATA[('h, _)]]></html:span>
                        <html:span class="ocaml-entity-name-function-binding">contents_key</html:span>
                        <html:span class="ocaml-source"> = 'h
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">'h </html:span>
                        <html:span class="ocaml-entity-name-function-binding">node_key</html:span>
                        <html:span class="ocaml-source"> = 'h
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword">type</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">'h </html:span>
                        <html:span class="ocaml-entity-name-function-binding">commit_key</html:span>
                        <html:span class="ocaml-source"> = 'h
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword-other-ocaml">module</html:span>
                        <html:span class="ocaml-source"><![CDATA[ Make : (C : Irmin__.Contents.S) ->]]></html:span>
                        <html:span class="ocaml-keyword-other-ocaml">sig</html:span>
                        <html:span class="ocaml-source"> ... </html:span>
                        <html:span class="ocaml-keyword-other">end</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword-other">end</html:span>
                        <html:span class="ocaml-source">
</html:span>
                      </html:code>
                    </html:pre>
                    <html:p>I think it is fair to say the documentation is hard to follow as it is a module and functor soup. For example, looking at <html:code>irmin.3.11.0</html:code>, starting at <fr:link href="https://ocaml.org/p/irmin/latest/doc/index.html" type="external">the toplevel documentation page</fr:link> our path to finding this paricular module and functor is as follows:</html:p>
                    <html:ol>
                      <html:li>
                        <html:p>We jump into <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin.mem/Irmin_mem/index.html" type="external"><html:code>Irmin_mem</html:code></fr:link> from the nicely written landing page.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We scroll down to find <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin.mem/Irmin_mem/index.html#module-KV" type="external">the KV module</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We now make sense of the module's signature by following the <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/index.html" type="external">KV_maker link</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>We see a <html:code>Make (C : Contents.S) : sig ... end</html:code> at the end of the module, and <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/Make/index.html#module-Schema" type="external">we navigate through that</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Finally we have come to our journey's end, and find the <fr:link href="https://ocaml.org/p/irmin/latest/doc/irmin/Irmin/module-type-KV_maker/Make/index.html#module-Schema" type="external">schema module</fr:link> with type constraints like <html:code>type Branch.t = string</html:code>.</html:p>
                      </html:li>
                    </html:ol>
                    <html:p>There is a big assumption there that you know what the <html:code>Schema</html:code> module is telling you and how it relates to your "store".</html:p>
                    <html:p>There is a counter-argument here, in that Irmin is incredibly flexible in terms of what you can use as types for your keys, branches, hashes etc. I was quite easily able to produce <fr:link href="https://github.com/patricoferris/ocaml-cid/blob/main/test/irmin_cid.ml" type="external">Irmin stores that use CIDs (self-describing content identifiers)</fr:link> for example.</html:p>
                    <html:p>I think there is a middle ground. For Irmin to be usable it needs to reduce the complexity of the API. The complexity is due to, in large part, over-functorisation. If the functors cannot be removed then perhaps better documentation or more <fr:link href="https://ocaml.org/p/irmin-containers/latest/doc/irmin-containers/Irmin_containers/index.html" type="external">introductory libraries like irmin-containers</fr:link> would be helpful. Perhaps a <html:em>standalone</html:em> library that acts as an interface to Irmin stores would be helpful. I find myself time and again implementing <fr:link href="https://github.com/fn06/shelter/blob/main/src/lib/store.ml" type="external">something like that</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Backends Galore">Backends Galore</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Irmin has plenty of backends including <fr:link href="https://ocaml.org/p/irmin-git/latest" type="external">a git-compatible one</fr:link>, <fr:link href="https://ocaml.org/p/irmin-mirage/latest" type="external">a MirageOS backend</fr:link>, <fr:link href="https://ocaml.org/p/irmin-indexeddb/latest" type="external">an in-browser IndexedDB backend</fr:link> and even a <fr:link href="https://github.com/andreas/irmin-fdb" type="external">FoundationDB backend</fr:link>.</html:p>
                    <html:p><fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> needs to have fewer, better tested backends. Of course, some of these are likely driven by funding and use-case specific details. However, I think by focusing on a few key backends and striving for solid performance but also strong consitency guarantees, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> would become a more viable candidate for potential users. I also believe the browser backend plays a key part to making this work in order to facilate <fr:link href="https://lofi.so/" type="external">local-first applications</fr:link>.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Syncing Remote Stores">Syncing Remote Stores</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The <fr:link href="https://ocaml.org/p/irmin/3.11.0/doc/irmin/Irmin/Sync/index.html" type="external">synchronisation mechanisms in Irmin</fr:link> are powerful, but often the API is very confusing. For example, with the git-compatible Unix backend, nested deep in the documentation is the function required to create a <fr:link href="https://ocaml.org/p/irmin-git/latest/doc/irmin-git.unix/Irmin_git_unix/Maker/Make/index.html#val-remote" type="external">remote endpoint</fr:link>. Once they have found this function, using it is not easy as it requires them to learn about the <fr:link href="https://ocaml.org/p/mimic/latest" type="external"><html:code>Mimic.ctx</html:code></fr:link>, which is an abstraction of the networking stack!</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Do Fewer Things and Do Them Well">Do Fewer Things and Do Them Well</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Irmin is simultaneously a database that supports: content-addressing, merging, key-value lookup, branches, transactions, complete OS portability etc. I think, in short, it tries to do too many things and comes up short on some of them in ways that really matter.</html:p>
                    <html:p>When building the <fr:link href="https://github.com/carboncredits/retirement-db" type="external">content-addressed database</fr:link> I needed strong guarantees about some atomic actions to perform on the underlying store. For example, <fr:link href="https://github.com/mirage/irmin/issues/2073" type="external">setting the value and accessing the commit associated with it</fr:link> which was not possible with the API at that time in an atomic way. This kind of missing functionality is probably only understood after users stumble across it, but it also makes the library feel less focused and ready for production use-cases.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Documentation">Documentation</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>It will probably come as no surprise that one of the main limitations of using <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> is the lack of documentation and tutorials. This is a particular pain point as the API is not very straightforward.</html:p>
                <html:p>A while back, I started an <fr:link href="https://patricoferris.github.io/irmin-book/" type="external">Irmin book</fr:link> intending to help document the kinds of things real-world users would need in order to use <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> in earnest. For example: ways to <fr:link href="https://patricoferris.github.io/irmin-book/contents/versioned-data.html" type="external">deal with type migrations</fr:link> or <fr:link href="https://patricoferris.github.io/irmin-book/arch/runtime-types.html" type="external">primers on runtime types</fr:link>. I still believe this sort of work would be invaluable, but there is a large cost to completing it, and it is not clear if there is enough interest in the project to warrant such an effort.</html:p>
                <html:p>The <fr:link href="https://irmin.org/tutorial/introduction/" type="external">tutorials on the irmin website</fr:link> are still good starting points for most new users. But they quickly lack the depth for real-world scenarios.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>8</fr:month>
                  <fr:day>7</fr:day>
                </fr:date>
                <fr:title text="Feature Wishlist">Feature Wishlist</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>What follows are additional ideas for improving <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>.</html:p>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Heterogeneous Stores">Heterogeneous Stores</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><![CDATA[For all of [Irmin]'s abstraction and functorisation, there is a very clear]]> missing feature for lots of first-time users of the library: you can only store values of a single type.</html:p>
                    <html:p>This leads to a few common workarounds:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Storing a serealised version of your values, essentially escaping the type-system and implementing a form of dynamic typing.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Growing your value to hold lots of different types via some large variant type.</html:p>
                      </html:li>
                    </html:ul>
                    <html:p>Both of these options are feasible and have been used in practice. However, they are workarounds. A long time ago <fr:link href="https://craigfe.io/" type="external">CraigFe</fr:link> created an <fr:link href="https://github.com/mirage/irmin/issues/909" type="external">RFC for heterogeneous stores</fr:link>, which I think about a lot. The main idea is to augment <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> paths (keys) to be GADTs that carry type information about the kinds of values they access (similar to <fr:link href="https://ocaml.org/p/hmap" type="external">heterogeneuous variants of other data structures</fr:link>). Something like this alongside a simplified API would make Irmin more appealing as a library for persistent data storage.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Real-world Retrospectives">Real-world Retrospectives</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>This echos some thoughts from the <html:em>Documentation</html:em> section. There are some very real-world <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> use-cases out there. For example, for a long time (I'm not sure if this is still the case) parts of the <fr:link href="https://ocaml.org/p/tezos-context/latest#dependencies" type="external">Tezos blockchain were using Irmin</fr:link> which uses the <fr:link href="https://ocaml.org/p/irmin-pack/latest" type="external">irmin-pack</fr:link> backend. Does this make irmin-pack the best tested backend and perhaps should be the default backend for new users? Or is it hyper-specific to the Tezos use case? There are <fr:link href="https://tarides.com/blog/2020-09-01-introducing-irmin-pack/" type="external">blogs on tarides.com about the irmin-pack backend</fr:link>, but they might be outdated and should not be the first place to find advice on which Irmin backend to use.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>8</fr:month>
                      <fr:day>7</fr:day>
                    </fr:date>
                    <fr:title text="Active Development and Engagement">Active Development and Engagement</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>As far as I know, <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> was at the forefront of technologies that have come to be described as <fr:link href="https://lofi.so/" type="external">local-first</fr:link>. There is a growing interest in this area (particularly as it acts as a counter-argument to an increasingly online, centralised model). I highly recommend reading <fr:link href="https://patrick.sirref.org/ink &amp; switch's essay on the matter/" type="external">Ink &amp; Switch's essay on the matter</fr:link>. And it would be great to see more research via <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> at things like <fr:link href="https://lu.ma/localfirstswunconf-stlouis" type="external">the lofi unconference</fr:link> and the <fr:link href="https://2023.splashcon.org/home/plf-2023" type="external">PLF workshop at SPLASH 2023</fr:link>!</html:p>
                    <html:p>Thank you for reading! And thank you to all the <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link> contributors. I hope this might be useful in the future for building the next-generation <fr:link href="/irmin/" title="Irmin" uri="https://patrick.sirref.org/irmin/" display-uri="irmin" type="local">Irmin</fr:link>!</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>18</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-07-18/</fr:uri>
            <fr:display-uri>weekly-2025-07-18</fr:display-uri>
            <fr:route>/weekly-2025-07-18/</fr:route>
            <fr:title text="Back to shelter">Back to shelter</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Capnproto Interface to Shelter">Capnproto Interface to Shelter</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent some time this week thinking about decoupling <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>'s builds from the CLI tool. This would allow users to connect to a remote daemon to build and store their sessions, opening up the possibility of using <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> on Windows and macOS.</html:p>
                <html:p>The design so far keeps the metadata local, in an <fr:link href="https://irmin.org/" type="external">Irmin</fr:link> database. I will probably then augment the stored information with some kind of unique daemon identifier to know where the actual data is.</html:p>
                <html:p>This is all still quite fresh, and I will have more by the end of next week.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="OCaml-related Things">OCaml-related Things</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Something I decided to do last week, was to make a clearer delineation between my OCaml work and research. That line is not always very distinct, but I have split of a separate set of <fr:link href="https://patrick.sirref.org/ocaml-weeklies/" type="external">weeklies for OCaml related things</fr:link>.</html:p>
                <html:p>Fear not, the <fr:link href="https://patrick.sirref.org/ocaml-weeklies/" type="external">OCaml weeklies</fr:link> are a subset of these weeklies and so I will, when I remember, transclude them for you.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>15</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/ocaml-weekly-2025-w29/</fr:uri>
                    <fr:display-uri>ocaml-weekly-2025-w29</fr:display-uri>
                    <fr:route>/ocaml-weekly-2025-w29/</fr:route>
                    <fr:title text="OCaml Weekly 2025 w29">OCaml Weekly 2025 w29</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:title text="Ppxlib">Ppxlib</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I met with <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> this week to discuss future plans for <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. The current state of affairs is that <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> is becoming unmaintainable. This is primarily a knock-on effect from changes being made to OCaml's parsetree (e.g. labelled tuples being added in 5.4). <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> has a plan that will provide two key properties.</html:p>
                        <html:ol>
                          <html:li>
                            <html:p>Migrations, which allow old compilers to be used with new <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> releases, will be more compatible. For example, we will be able to migrate new features downwards and back up without raising an error.</html:p>
                          </html:li>
                          <html:li>
                            <html:p>Ppx authors will be able to use new features in an opt-in workflow, rather than <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> bumping the internal AST (like we did <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">in ppxlib.0.36.0</fr:link>). This will reduce the maintenance burden significantly whilst still allowing users to write ppxes for new OCaml features.</html:p>
                          </html:li>
                        </html:ol>
                        <html:p>I also started looking into some older issues in <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> related to performance. This is work-in-progress, but I am trying to improve the performance of some passes done by <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. To better understand what was making <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> slow, I wanted to use <fr:link href="https://github.com/tarides/runtime_events_tools" type="external">runtime_events_tools</fr:link> but I was dismayed to see it wanting to install over 100 packages! I <fr:link href="https://github.com/tarides/runtime_events_tools/pull/57" type="external">opened a PR to reduce the number of packages</fr:link>. I think this kind of work goes a little unrecognised as it is not very glamorous. However, I think it really benefits the OCaml community in the long run.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:title text="Outreachy">Outreachy</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>In <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> news, we had a wonderful mid-internship video call with all the interns and mentors to catch-up on how everyone is getting along. Seeing the progress everyone has made was great! I am very grateful for the work that <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> and <fr:link href="https://github.com/gridbugs" type="external">Steve</fr:link> have put in so far to make this a very successful Outreachy round for OCaml.</html:p>
                        <html:p>In sadder news, an email was shared with all <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> mentors detailing the increasingly critical financial situation the project finds itself in. There are ongoing discussions about how costs can be cut including potentially only running a single round a year.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>15</fr:day>
                        </fr:date>
                        <fr:title text="Graft">Graft</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>With the release of <fr:link href="https://patrick.sirref.org/Forester/" type="external">Forester.5.0</fr:link>, I made a plan to make a release of <fr:link href="https://patrick.sirref.org/Graft/" type="external">Graft.0.1</fr:link>. Unfortunately this is blocked by a new release of <fr:link href="https://github.com/ocaml/opam-repository/pull/28172" type="external">hilite</fr:link>, a tool I built for doing build-time syntax highlighting for OCaml code. This powers the syntax highlighting on <fr:link href="https://ocaml.org/" type="external">ocaml.org</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>7</fr:month>
              <fr:day>18</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/ocaml-quarterly-q2/</fr:uri>
            <fr:display-uri>ocaml-quarterly-q2</fr:display-uri>
            <fr:route>/ocaml-quarterly-q2/</fr:route>
            <fr:title text="Quarterly OCaml Q2">Quarterly OCaml Q2</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Thanks to <fr:link href="https://patrick.sirref.org/tarides/" type="external">Tarides</fr:link> sponsorship, I get to work on open-source OCaml. This quarterly is a companion to my <fr:link href="/weeklies/" title="Patrick Ferris' Weeklies" uri="https://patrick.sirref.org/weeklies/" display-uri="weeklies" type="local">weeklies</fr:link>, summarising the last three months of development, peppered with ideas and thoughts about OCaml, its community and its future.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What I wanted to work on?">What I wanted to work on?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>There were two main things I hoped to <html:em>continue</html:em> working on: <html:strong>ppxlib</html:strong> and <html:strong>outreachy</html:strong>. These are projects that I was previously working on, and in the case of Outreachy I have now been involved for many years.</html:p>
                <html:p>In addition to this, all of my <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">Part II</fr:link> projects this year used OCaml in some regard. In general, I want to see more adoption of OCaml. Over the years this has taken many forms including <fr:link href="https://ocaml-explore.netlify.app/" type="external">my initial work on developing workflows for OCaml that just turned five years old</fr:link>. This directly fed into the rebranding and rethinking of <fr:link href="https://ocaml.org/" type="external">ocaml.org</fr:link> itself.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What I worked on?">What I worked on?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Ppxlib">Ppxlib</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> is the de facto standard library for building OCaml preprocessors. At the time of writing, <html:code>opam list --depends-on=ppxlib</html:code> informs me that there are 267 reverse dependencies. <fr:link href="https://www.janestreet.com/" type="external">Janestreet</fr:link> is a heavy user of ppxes and has <fr:link href="https://github.com/orgs/janestreet/repositories?language=&amp;amp;q=ppx&amp;amp;sort=&amp;amp;type=all" type="external">authored many</fr:link>.</html:p>
                    <html:p>One of the main accomplishments this quarter was <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">bumping the internal AST to 5.2</fr:link>. This allows ppx authors to use new OCaml language features in their ppxes. In bumping the AST, we knowingly broke compatability for pretty much every single reverse dependency. As best we can, we have been sending patches to ppx libraries and helping users migrate to the latest <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>.</html:p>
                    <html:p>There is an interesting dicussion to had about the nature of open-source, and its interaction with industrial monorepos and community tended package repositories. Package ecosystems thrive whenever there is a dedicated community creating, maintaining and publishing packages. The idea is that the published world should be healthy. The publishing medium can act as natural limiting factor in the churn of breaking changes (in the case of OCaml this is via <fr:link href="https://github.com/ocaml/opam-repository/" type="external">PRs to the opam-repository</fr:link>). This, I have come to notice, reacts poorly to changes coming from internally consistent monorepos where introducing breaking changes is easily fixed by applying patches there and then. Whatsmore, OCaml is often stated as an incredibly safe language to perform large refactorings thanks to its type system.</html:p>
                    <html:p><fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link> sits awkwardly in the space of possible breaking changes. Tied to OCaml's parsetree, impacts of changes there ripple down to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>. The compiler itself can remain internally consistent, and is protected as it need only parse source code. <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">Ppxlib</fr:link>, on the other hand, exposes the parsetree to users and thus any changes to the parsetree will likely be felt by ppx authors. Since I started working on <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link>, it feels as though the number of syntax changes has gone up (primarily from Janestreet work). Unless we make changes to how we provide support for these, maintainers of <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> will forever be stuck doing busy work! Thankfully, <fr:link href="/nathanreb/" title="Nathan Rebours" uri="https://patrick.sirref.org/nathanreb/" display-uri="nathanreb" type="local">Nathan</fr:link> <fr:link href="/ocaml-weekly-2025-w29/" title="OCaml Weekly 2025 w29" uri="https://patrick.sirref.org/ocaml-weekly-2025-w29/" display-uri="ocaml-weekly-2025-w29" type="local">has thoughts on how to improve this</fr:link>.</html:p>
                    <html:p>There are a slew of other features I have added to <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>Support for deriving from classes.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Support for deriving from module bindings and signatures.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Fixing compiler and ppxlib dummy locations.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Bumping to 5.3.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>Migrations for 5.4.</html:p>
                      </html:li>
                    </html:ul>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Outreachy">Outreachy</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Our two projects this year, one on <fr:link href="https://github.com/claudiusFX/claudius" type="external">claudius</fr:link> and one on <fr:link href="https://github.com/ocaml/dune" type="external">dune</fr:link>, are going extremely well. At the time of writing, we just had <fr:link href="/ocaml-weekly-2025-w29/" title="OCaml Weekly 2025 w29" uri="https://patrick.sirref.org/ocaml-weekly-2025-w29/" display-uri="ocaml-weekly-2025-w29" type="local">a mid-internship call to catch up</fr:link>, and I was blown away by the progress each intern has made. Unfortunately, <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> is struggling with funding and the next round is perhaps not going to happen. This is a real shame and I am hoping that it will not be the case.</html:p>
                    <html:p>Outreachy has been a wonderful source of new, committed OCaml developers. If you haven't already, do peruse the <fr:link href="https://ocaml.org/outreachy" type="external">webpage on OCaml.org</fr:link> to see past internships or <fr:link href="https://watch.ocaml.org/c/outreachy_ocaml/videos" type="external">watch the demo day presentations</fr:link>. For the mentors involved, I believe it has also been a rewarding experience (though at times a challenging one). We are always looking for new mentors and project ideas, please <fr:link href="/patrickferris/" title="Patrick Ferris" uri="https://patrick.sirref.org/patrickferris/" display-uri="patrickferris" type="local">do reach out to me</fr:link> if you are interested.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Hazel">Hazel</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>OCaml's feature set allows it to shine at writing programming languages (and things of that ilk: compilers, interpretters, static analysis tools). <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> is a research programming language with typed holes written completely in OCaml (via the <fr:link href="https://reasonml.github.io/" type="external">reason dialect</fr:link>).</html:p>
                    <html:p>Relating this back to the original intent of my work, to improve OCaml adoption, I believe this also means keeping existing users happy. In the last quarter I developed a compiler from <fr:link href="/hazel_of_ocaml/" title="hazel_of_ocaml" uri="https://patrick.sirref.org/hazel_of_ocaml/" display-uri="hazel_of_ocaml" type="local">OCaml to Hazel</fr:link>. Whilst new features are still being added to <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link>, I hope this could serve as a tool to help develop test-suites and standard library functions using existing OCaml solutions. In a student's work (<fr:link href="/part-ii-hazel/" title="Type Error Debugging in Hazel" uri="https://patrick.sirref.org/part-ii-hazel/" display-uri="part-ii-hazel" type="local">Typed Debugging for Hazel</fr:link>), we used this tool to build a corpus of ill-typed <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> programs to great effect.</html:p>
                    <html:p>OCaml should continue to be a world-class programming language for building other programming languages. I hope to upstream some of this work to <fr:link href="/hazel/" title="Hazel" uri="https://patrick.sirref.org/hazel/" display-uri="hazel" type="local">Hazel</fr:link> and provide some low effort maintenance to help keep their compiler in good shape.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Systems Programming in OCaml">Systems Programming in OCaml</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>In a cross-over with my own research, I have been developing many tools related to systems programming in OCaml including:</html:p>
                    <html:ul>
                      <html:li>
                        <html:p>An eBPF-based <fr:link href="/open-trace/" title="Opentrace" uri="https://patrick.sirref.org/open-trace/" display-uri="open-trace" type="local"><html:code>open</html:code> syscall tracing tool</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>A library in OCaml for <fr:link href="https://github.com/quantifyearth/void" type="external">spawning void processes</fr:link>.</html:p>
                      </html:li>
                      <html:li>
                        <html:p>A <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shell session manager</fr:link> that uses <fr:link href="https://irmin.org/" type="external">Irmin</fr:link> to manage sessions. It is nice to see a new push to <fr:link href="https://github.com/mirage/irmin/pull/2149" type="external">finally land the direct-style Irmin PR</fr:link>!</html:p>
                      </html:li>
                    </html:ul>
                    <html:p>This work is means to develop the underlying libraries that support it. For example, I have opened a few PRs to <fr:link href="https://github.com/ocaml-multicore/eio" type="external">Eio</fr:link> to add new "fork actions" to the spawn API. I also investigated the feasibility of changing the underlying mechanisms in <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> to use <fr:link href="https://github.com/ocaml-multicore/picos" type="external">Picos</fr:link>. In the future, I think this could be important avoid further splitting the OCaml ecosystem.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>7</fr:month>
                          <fr:day>18</fr:day>
                        </fr:date>
                        <fr:title text="OxCaml">OxCaml</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>I dabbled a little with <fr:link href="https://oxcaml.org/" type="external">OxCaml</fr:link> and build <fr:link href="/try-oxcaml/" title="Try OxCaml" uri="https://patrick.sirref.org/try-oxcaml/" display-uri="try-oxcaml" type="local">try-oxcaml</fr:link> to let people take it for a spin without having to perform opam repository gymnastics. It turned into a lot of work to track down some pretty inane bugs (type definitions differeing between js_of_ocaml and the OxCaml compiler, resulting in different Javascript runtime representations...).</html:p>
                        <html:p>This unblocked a few of my colleagues to get OxCaml working on tools like <fr:link href="https://jon.recoil.org/notebooks/foundations/foundations1.html" type="external">odoc_notebooks</fr:link> and <fr:link href="https://github.com/art-w/x-ocaml" type="external">x-ocaml</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>7</fr:month>
                      <fr:day>18</fr:day>
                    </fr:date>
                    <fr:title text="Forester">Forester</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>A good proportion of my work this quarter has been focused on how to present the very work that I am doing. <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link> has been developing a tool for scientific thought called <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> which seemed like a possible candidate for writing and sharing my work.</html:p>
                    <html:p>Porting my existing blog posts and website content from markdown to Forester's LaTeX-inspired syntax didn't seem like an option. In particular, many of my posts made use of additional markdown-based tools (like <fr:link href="https://github.com/realworldocaml/mdx" type="external">ocaml-mdx</fr:link>).</html:p>
                    <html:p>This lead to the development of <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">Graft</fr:link>: a preprocessor for Forester forests, converting markdown and bibtex to trees.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="What's next?">What's next?</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>So, I worked on most of what I wanted to work on and then some! Going forward I hope to keep maintaining <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> in some capacity and coordinating the OCaml community's <fr:link href="/outreachy/" title="Outreachy" uri="https://patrick.sirref.org/outreachy/" display-uri="outreachy" type="local">Outreachy</fr:link> efforts.</html:p>
                <html:p>I hope to continue my small experiments (e.g. converting Eio to Picos). My own research makes heavy use of Irmin, and I would be interested to help with that too. More recently, a new library has been released for working with numerical data in OCaml called <fr:link href="https://github.com/raven-ml/" type="external">Raven</fr:link>: I am interested to use this library in <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link>, a suite of geospatial tools written in OCaml that I maintain.</html:p>
                <html:p>I feel conflicted about the <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> efforts. I admit, I am not fully aware of the full benefits of the features, but I worry about some proliferation of modes that make the type system in OCaml unbearable to use. On top of this, with my <fr:link href="/ppxlib/" title="Ppxlib" uri="https://patrick.sirref.org/ppxlib/" display-uri="ppxlib" type="local">ppxlib</fr:link> hat on, I worry about the impact of changing the compiler so frequently, placing strain on an already small community. That being said, by releasing <fr:link href="https://patrick.sirref.org/oxcaml/" type="external">OxCaml</fr:link> separately I do believe running it as an experimental set of packages will help understand the tool better. But I would not be building anything I intend to maintain or research with right now as that ecosystem is far too volatile.</html:p>
                <html:p>Finally, over the past two years I have done a lot of teaching. From <fr:link href="/part-ii/" title="Part II Projects" uri="https://patrick.sirref.org/part-ii/" display-uri="part-ii" type="local">Part II projects</fr:link> to <fr:link href="/focs/" title="Foundations of Computer Science" uri="https://patrick.sirref.org/focs/" display-uri="focs" type="local">supervisions</fr:link>. Going into next (academic) year, I intend to reduce my in-person teaching to focus on my research. However, I am interested in producing more materials for learning, maybe some of this in OCaml, perhaps something similar to <fr:link href="https://beautifulracket.com/" type="external">Beautiful Racket</fr:link>. I have tried in the past to do these sorts of things, for example <fr:link href="https://patricoferris.github.io/irmin-book/" type="external">The Irmin Book</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>7</fr:month>
                  <fr:day>18</fr:day>
                </fr:date>
                <fr:title text="Thank you">Thank you</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Thank you for reading this wrap up! And thank you again to <fr:link href="https://patrick.sirref.org/tarides/" type="external">Tarides</fr:link> for letting me work so freely on things that I think are good for the OCaml community.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>6</fr:month>
              <fr:day>2</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-06-02/</fr:uri>
            <fr:display-uri>weekly-2025-06-02</fr:display-uri>
            <fr:route>/weekly-2025-06-02/</fr:route>
            <fr:title text="Forester as a Target Syntax">Forester as a Target Syntax</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>This week included some time finishing <fr:link href="/open-trace/" title="Opentrace" uri="https://patrick.sirref.org/open-trace/" display-uri="open-trace" type="local">opentrace</fr:link> and subsequently folding it into <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link>. I have been writing up some more of the draft paper for <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link> which I am excited to share in the near future.</html:p>
            <html:p>I revisited the <fr:link href="/vpnkit-upgrade/" title="Defunctorising VPNKit" uri="https://patrick.sirref.org/vpnkit-upgrade/" display-uri="vpnkit-upgrade" type="local">upgrading vpnkit</fr:link> PR and pushed some more fixes. I have been thinking, again, about the promise of a direct-style world for OCaml that just hasn't quite landed yet. <html:em>C'est la vie</html:em>.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Forester and Graft">Forester and Graft</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent a bit of time finally pulling out my changes to <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> to add markdown and bibtex support into a standalone tool: <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link>.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>6</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:uri>https://patrick.sirref.org/graft/</fr:uri>
                    <fr:display-uri>graft</fr:display-uri>
                    <fr:route>/graft/</fr:route>
                    <fr:title text="Graft">Graft</fr:title>
                    <fr:meta name="external">https://github.com/patricoferris/graft</fr:meta>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Graft is a <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> preprocessor.</html:p>
                    <html:p>It takes a forester (a directory of trees) written in a mixture of Markdown, Bibtex and <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> syntax and produces a new forest completely written in <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> syntax.</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>6</fr:month>
                          <fr:day>2</fr:day>
                        </fr:date>
                        <fr:title text="Usage">Usage</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p><html:code>graft</html:code> simply preprocesses a forest generating Forester trees from <html:code>.md</html:code>, <html:code>.bib</html:code> and <html:code>.tree</html:code> files. It will copy the structure of the input directory in the output directory.</html:p>
                        <html:pre class="hilite">
                          <html:code>
                            <html:span class="sh-source">$ graft preprocess --output=grafted-trees trees
</html:span>
                            <html:span class="sh-source">$ forester build
</html:span>
                          </html:code>
                        </html:pre>
                        <html:p>This assumes that you have updated your Forester <html:code>toml</html:code> file to put the <html:code>grafted-trees</html:code> directory as your source of trees.</html:p>
                        <html:pre><![CDATA[[forest]
trees = [ "grafted-trees" ]]]></html:pre>
                      </fr:mainmatter>
                    </fr:tree>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:date>
                          <fr:year>2025</fr:year>
                          <fr:month>6</fr:month>
                          <fr:day>2</fr:day>
                        </fr:date>
                        <fr:title text="Example">Example</fr:title>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>A typical "tree" might look something like</html:p>
                        <html:pre><![CDATA[---
title: Opentrace and Supervisions
date: 2025-05-26
author: Patrick Ferris
---

Over the past two weeks I have mainly split my time (amongst many things) developing [opentrace](open-trace)
and doing revision supervisions.

```forester
\put\transclude/numbered{false}
\transclude{open-trace}
```]]></html:pre>
                        <html:p>A few things to note:</html:p>
                        <html:ol>
                          <html:li>
                            <html:p>The <html:code>yaml</html:code> frontmatter allows you to add some of the metadata fields from Forester.</html:p>
                          </html:li>
                          <html:li>
                            <html:p>At any point in your markdown there is an escape hatch to Forester using a <html:code>forester</html:code> codeblock.</html:p>
                          </html:li>
                        </html:ol>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
                <html:p>It is very satisfying to find the separation of concerns works quite well. For a while I had been rebasing my development branch on <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link>. I was also worried about trying to get the code upstream as it pulled in many dependencies. It seems that I have a very workable solution. I welcome contributions to <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> including extra input formats. I am also considering extending the <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> configuration to contain some <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> configuration for how it should generate new trees (e.g. at the moment every entry in a bibtex file is given a new tree).</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>6</fr:month>
                      <fr:day>2</fr:day>
                    </fr:date>
                    <fr:title text="Maths Support">Maths Support</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>As part of that process, <fr:link href="/graft/" title="Graft" uri="https://patrick.sirref.org/graft/" display-uri="graft" type="local">graft</fr:link> now supports Markdown KaTeX. For example:</html:p>
                    <fr:tree show-metadata="false" numbered="false">
                      <fr:frontmatter>
                        <fr:authors>
                          <fr:author>
                            <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                          </fr:author>
                        </fr:authors>
                        <fr:uri>https://patrick.sirref.org/mrdts/</fr:uri>
                        <fr:display-uri>mrdts</fr:display-uri>
                        <fr:route>/mrdts/</fr:route>
                        <fr:title text="Mergeable Replicated Data Type Implementation">Mergeable Replicated Data Type Implementation</fr:title>
                        <fr:taxon>Definition</fr:taxon>
                      </fr:frontmatter>
                      <fr:mainmatter>
                        <html:p>A <html:strong>mergeable replicated data type (MRDT) implementation</html:strong> for a data type <fr:tex display="inline"><![CDATA[\tau ]]></fr:tex> is a tuple <fr:tex display="inline"><![CDATA[D_{\tau } = (\Sigma , \sigma _{0}, do, merge)]]></fr:tex> where:</html:p>
                        <html:ul>
                          <html:li>
                            <html:p><fr:tex display="inline"><![CDATA[\Sigma ]]></fr:tex> is the set of all possible states at a branch,</html:p>
                          </html:li>
                          <html:li>
                            <html:p><fr:tex display="inline"><![CDATA[\sigma _{0} \in  \Sigma ]]></fr:tex> is the initial state,</html:p>
                          </html:li>
                          <html:li>
                            <html:p><fr:tex display="inline"><![CDATA[do : Op_{\tau } \times  \Sigma  \times  Timestamp \rightarrow  \Sigma  \times  Val_{\tau }]]></fr:tex> implements every data type operation,</html:p>
                          </html:li>
                          <html:li>
                            <html:p><fr:tex display="inline"><![CDATA[merge : \Sigma  \times  \Sigma  \times  \Sigma  \rightarrow  \Sigma ]]></fr:tex> implements the <html:em>three-way merge strategy</html:em>.</html:p>
                          </html:li>
                        </html:ul>
                        <html:p><fr:link href="/kcrsk-mrdts-2022/" title="Certified mergeable replicated data types" uri="https://patrick.sirref.org/kcrsk-mrdts-2022/" display-uri="kcrsk-mrdts-2022" type="local">Definition 2.1 from "Certified Mergeable Replicated Data Types"</fr:link>.</html:p>
                      </fr:mainmatter>
                    </fr:tree>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>2</fr:day>
                </fr:date>
                <fr:title text="Revision Supervisions">Revision Supervisions</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I have been doing revision supervisions for <fr:link href="/discrete-maths/" title="Discrete Mathematics" uri="https://patrick.sirref.org/discrete-maths/" display-uri="discrete-maths" type="local">Discrete Maths</fr:link> and <fr:link href="https://patrick.sirref.org/focs.md" type="external">Foundations of Computer Science</fr:link>. I have also been marking Operating Systems past paper questions for the same group of first years.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>4</fr:month>
              <fr:day>21</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-04-21/</fr:uri>
            <fr:display-uri>weekly-2025-04-21</fr:display-uri>
            <fr:route>/weekly-2025-04-21/</fr:route>
            <fr:title text="Shelter in the Forest">Shelter in the Forest</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>I spent much of this week working on Shelter and things related to it. Some of that time was also spent on Forester.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Forester">Forester</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I added two important quality-of-life features to my frontend to Forester this week.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>21</fr:day>
                    </fr:date>
                    <fr:title text="Bibtex Support">Bibtex Support</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I had previously mentioned adding support to <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> for <fr:link href="/weekly-2025-01-20/" title="Forester, ICFP, Wikis" uri="https://patrick.sirref.org/weekly-2025-01-20/" display-uri="weekly-2025-01-20" type="local">Markdown</fr:link>. This week I added support for Bibtex too. From any <html:code>*.bib</html:code> file in your forest, <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link> will now dutifully recognise it as a Bibtex file and convert, as best it can, all the entries into <html:code>Reference</html:code> trees.</html:p>
                    <html:p>I'm becoming quite convinced of this model at the moment. I'm using Forester's <html:code>Code.t</html:code> as a target representation. In fact, to ease the process, I really shouldn't spend <html:em>all my time</html:em> on my website, I have reused my <html:code>Yaml.t -&gt; Code.t</html:code> and <html:code>Markdown.t -&gt; Code.t</html:code> functions in the Bibtex parser.</html:p>
                    <html:p>To see it in action, you could have a look at the <fr:link href="/mokhov-build-systems/" title="Build systems a la carte" uri="https://patrick.sirref.org/mokhov-build-systems/" display-uri="mokhov-build-systems" type="local">Build Systems à la Carte</fr:link> paper which is generated completely from Bibtex.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>21</fr:day>
                    </fr:date>
                    <fr:title text="Full Heading Support">Full Heading Support</fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>The eagled-eyed viewer may have noticed that the table of contents for this page has <html:em>more than one level</html:em>. I finally caved and spent an evening rejigging my <html:code>Cmarkit.Doc.t -&gt; Tree</html:code> code which was hacky and broken and is now less hacky and less broken.</html:p>
                    <html:p>In addition, headings support links and emphasis etc.</html:p>
                  </fr:mainmatter>
                </fr:tree>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>21</fr:day>
                    </fr:date>
                    <fr:title text="Lunch with Jon Sterling">Lunch with <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link></fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>I had a delightful lunch with <fr:link href="/jonmsterling/" title="Jon Sterling" uri="https://patrick.sirref.org/jonmsterling/" display-uri="jonmsterling" type="local">Jon Sterling</fr:link> discussing the future of Forester, the nature of the Web (old and new) and the success posting weekly updates for our colleagues. Thanks Jon.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Shelter Fixes"><fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> Fixes</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I spent a good chunk of my week fixing bugs in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> with the aim to perhaps setup a VM somewhere and let people kick the tyres of what we've got so far.</html:p>
                <html:p>The first bug is pretty annoying. At the moment, our filsystem backend is ZFS and we make heavy use of snapshots and cloning in order to provide time-travelling capabilities. Unfortunately, ZFS will take a snapshot before data has fully made it to disk (or whatever is the equivalent point it should reach in ZFS). Commands that generated lots of disk activity would be snapshotted in a half finished state and this would cause all sorts of problems. Thanks to <fr:link href="https://patrick.sirref.org/mtelvers/" type="external">Mark Elvers</fr:link> for the pointer to how OBuilder uses ZFS for the OCaml macOS builders which unmount datasets immediately therefore inducing a <html:em>flush</html:em> of sorts. Shelter now follows a similar model with all of the slow downs that create. <fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link> and I discussed some amalgamation of overlayfs, tmpfs and ZFS to alleviate some of this but for now that's a premature optimisation.</html:p>
                <fr:tree show-metadata="false" numbered="false">
                  <fr:frontmatter>
                    <fr:authors>
                      <fr:author>
                        <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                      </fr:author>
                    </fr:authors>
                    <fr:date>
                      <fr:year>2025</fr:year>
                      <fr:month>4</fr:month>
                      <fr:day>21</fr:day>
                    </fr:date>
                    <fr:title text="A small eDSL for Shelter">A small eDSL for <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link></fr:title>
                  </fr:frontmatter>
                  <fr:mainmatter>
                    <html:p>Whilst testing <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>, I ended up wanting a way to programmatically invoke the different run commands. This is similar to say a Dockerfile, but maybe with a little more expressivity.</html:p>
                    <html:p>This lead me to revisit the <fr:link href="/mokhov-build-systems/" title="Build systems a la carte" uri="https://patrick.sirref.org/mokhov-build-systems/" display-uri="mokhov-build-systems" type="local">Build systems à la Carte</fr:link> paper and rediscover <fr:link href="/mokhov-selective-2019/" title="Selective applicative functors" uri="https://patrick.sirref.org/mokhov-selective-2019/" display-uri="mokhov-selective-2019" type="local">selective applicative functors</fr:link>.</html:p>
                    <html:p>I started playing around with a selective applicative interface to Shelter, this would allow you to express your dependencies statically but select them dynamically (as the paper says).</html:p>
                    <html:pre class="hilite">
                      <html:code>
                        <html:span class="ocaml-keyword-other">module</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">D</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">Shl</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">Identity</html:span>
                        <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-keyword">let</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">shelterfile</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword">let</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword">open</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">D</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other">in</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword">let</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">base_image</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">from</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-string-quoted-double">alpine</html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other">in</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword">let</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">is_node_lst</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">img</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">String</html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                        <html:span class="ocaml-source">equal</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-string-quoted-double">v22.15.0</html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                        <html:span class="ocaml-source">stdout</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">img</html:span>
                        <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other">in</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword">let</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">cmds</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">base</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-keyword">let</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-entity-name-function-binding">node_version</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-operator">=</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">run</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-string-quoted-double">node --version</html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">base</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-keyword-other">in</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">    </html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">Select</html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                        <html:span class="ocaml-source">if'</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">      </html:span>
                        <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                        <html:span class="ocaml-constant-language-capital-identifier">Select</html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                        <html:span class="ocaml-source">map</html:span>
                        <html:span class="ocaml-source"> ~</html:span>
                        <html:span class="ocaml-source">f</html:span>
                        <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                        <html:span class="ocaml-source">is_node_lst</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">node_version</html:span>
                        <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">      </html:span>
                        <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                        <html:span class="ocaml-source">run</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-string-quoted-double"><![CDATA[node -e 'console.log('success!')]]></html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">      </html:span>
                        <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                        <html:span class="ocaml-source">run</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-string-quoted-double"><![CDATA[node -e 'console.log('failure!')]]></html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">      </html:span>
                        <html:span class="ocaml-source">base</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-keyword-other">in</html:span>
                        <html:span class="ocaml-source">
</html:span>
                        <html:span class="ocaml-source">  </html:span>
                        <html:span class="ocaml-source">with_session</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-string-quoted-double">node</html:span>
                        <html:span class="ocaml-string-quoted-double">"</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                        <html:span class="ocaml-source">cmds</html:span>
                        <html:span class="ocaml-source"> </html:span>
                        <html:span class="ocaml-source">base_image</html:span>
                        <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                        <html:span class="ocaml-source">
</html:span>
                      </html:code>
                    </html:pre>
                    <html:p>From this, we get a slightly more expressive way to describe images.</html:p>
                  </fr:mainmatter>
                </fr:tree>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Geocaml TIFF Library"><fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">Geocaml</fr:link> TIFF Library</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I was pleasantly surprised to receive a pull request from <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> adding support to ocaml-tiff for reading TIFF files compressed using LZW. I was also surprised to hear the TIFF LZW is a little different to others.</html:p>
                <html:p>In trying to get this PR merged, I moved the initialisation of the Eio eventloop to outside each individual test case. This one change then completely broke the entire test suite. After a period of debugging and help from <fr:link href="/talex5/" title="Thomas Leonard" uri="https://patrick.sirref.org/talex5/" display-uri="talex5" type="local">Thomas Leonard</fr:link> the root cause was OCaml's <html:code>OUnit2</html:code> library using process-level parallelism (via <html:code>Unix.fork</html:code>), sharing the ring between the parent and the child lead to the issues.</html:p>
                <html:p><fr:link href="https://github.com/ocaml-multicore/eio/issues/801" type="external">Read more about that issue on the Eio issue tracker</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>4</fr:month>
                  <fr:day>21</fr:day>
                </fr:date>
                <fr:title text="Part II Students"><fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">Part II</fr:link> Students</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>As the new term begins, it signals that there are only just over two weeks for the final year undegrads at <fr:link href="/ucam/" title="University of Cambridge" uri="https://patrick.sirref.org/ucam/" display-uri="ucam" type="local">Cambridge</fr:link> to submit their dissertations.</html:p>
                <html:p>The four students that I help supervise have been sending me drafts of their work (and reminder you can <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">read about their projects</fr:link>) and I'm very impressed. I'm sure the next two weeks will be stressful, but I'm proud of what they have accomplished over the past academic year.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>3</fr:month>
              <fr:day>31</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/weekly-2025-03-31/</fr:uri>
            <fr:display-uri>weekly-2025-03-31</fr:display-uri>
            <fr:route>/weekly-2025-03-31/</fr:route>
            <fr:title text="Shelter, Hazel and More!">Shelter, Hazel and More!</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Last week I focused on <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> -- our idea that shells should have the same ability as reproducible build tools like Nix or Docker. To this end I now have a fairly fleshed out prototype.</html:p>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Shelter Prototype">Shelter Prototype</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>Shelter is a spin-off from the work <fr:link href="/mdales/" title="Michael W. Dales" uri="https://patrick.sirref.org/mdales/" display-uri="mdales" type="local">Michael</fr:link> and I started with <fr:link href="https://github.com/quantifyearth/shark" type="external">Shark</fr:link>. It takes the same ideas but applies them directly to a shell-like interface.</html:p>
                <html:p>We're still in the middle of working all of this, but you can read more about it at <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Forester Hacking">Forester Hacking</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>As you can probably tell, my website is still using <fr:link href="/forester/" title="Forester" uri="https://patrick.sirref.org/forester/" display-uri="forester" type="local">Forester</fr:link>. I rebased my Markdown branch to include the new Atom syndication feature.</html:p>
                <html:p>Alongside that I added support for arbitrary HTML injection into Forester via codeblocks in Markdown. This was actually very straightforward thanks to <fr:link href="https://ocaml.org/p/markup" type="external">Markup</fr:link> and being able to re-parse Forester syntax in the middle of converting a Markdown document. The HTML for the shell in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link> uses this feature.</html:p>
                <html:p>If you are interested in taking this custom Forester for a spin, there's <fr:link href="https://github.com/patricoferris/ocaml-forester/tree/5-dev-md" type="external">a branch on Github</fr:link>. In fact, nearly the only change beyond letting the core engine know about markdown files, is <fr:link href="https://github.com/patricoferris/ocaml-forester/blob/5-dev-md/lib/compiler/Parse_md.ml" type="external">adding a new parser frontend</fr:link>.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Hazel">Hazel</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>For one of my <fr:link href="/part-ii-2024/" title="Part II Students 2024" uri="https://patrick.sirref.org/part-ii-2024/" display-uri="part-ii-2024" type="local">Part II</fr:link> students, I've been prototyping a transpiler from OCaml to Hazel. This has gone pretty well and now supports type annotations as well as straight-forward implementation translation.</html:p>
                <html:p>Consider the following OCaml <html:code>map</html:code> function.</html:p>
                <html:pre class="hilite">
                  <html:code>
                    <html:span class="ocaml-keyword">let</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword">rec </html:span>
                    <html:span class="ocaml-entity-name-function-binding">map</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">f</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">=</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other">function</html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword-other">|</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-list"><![CDATA[[]]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-constant-language-list"><![CDATA[[]]]></html:span>
                    <html:span class="ocaml-source">
</html:span>
                    <html:span class="ocaml-source">  </html:span>
                    <html:span class="ocaml-keyword-other">|</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">x</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">xs</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                    <html:span class="ocaml-source">f</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">x</html:span>
                    <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">map</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">f</html:span>
                    <html:span class="ocaml-source"> </html:span>
                    <html:span class="ocaml-source">xs</html:span>
                    <html:span class="ocaml-source">
</html:span>
                  </html:code>
                </html:pre>
                <html:p>The tool, <fr:link href="https://github.com/patricoferris/hazel_of_ocaml" type="external"><html:code>hazel_of_ocaml</html:code></fr:link> can translate this to Hazel code, including making the polymorphism explicit.</html:p>
                <html:pre><![CDATA[let map : forall a -> forall b -> (a -> b) -> [a] -> [b] 
  = typfun a -> typfun b -> fun f -> fun x1 -> case x1
  | [] => []
  | x :: xs => f(x) :: map(f)(xs)
end in ?]]></html:pre>
                <html:p>You can copy and paste that codeblock into the <fr:link href="https://hazel.org/build/dev/" type="external">hazel playground</fr:link>. But do note that it still needs some manual editing to add the type applications in directly (<html:code>map@&lt;a&gt;@&lt;b&gt;</html:code>). With the right amount of type-inferencing and scoping I actually think that you could place those type applications in yourself. This could make a nice Part II project I think.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false" numbered="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2025</fr:year>
                  <fr:month>3</fr:month>
                  <fr:day>31</fr:day>
                </fr:date>
                <fr:title text="Ppxlib">Ppxlib</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>I recently wrote about the painful experience of <fr:link href="/ppxlib-5-2/" title="Bumping Ppxlib's AST to 5.2" uri="https://patrick.sirref.org/ppxlib-5-2/" display-uri="ppxlib-5-2" type="local">miragrating ppxlib to the 5.2 OCaml AST</fr:link>. This week, Nathan Rebours and I merged a PR to add the <fr:link href="https://github.com/ocaml-ppx/ppxlib/pull/558" type="external">5.3 AST</fr:link>! Ppxlib has been playing catch-up with the compiler and we decided it was best to try to catch up quickly and deal with the ecosystem fallout all at once rather than incrementally. With this new AST merged, ppx authors can now use the new <html:code>Pexp_effect</html:code> parsetree node. I'll write a little more about this in a separate post soon.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:uri>https://patrick.sirref.org/thesis-outline/</fr:uri>
            <fr:display-uri>thesis-outline</fr:display-uri>
            <fr:route>/thesis-outline/</fr:route>
            <fr:title text="Thesis Outline">Thesis Outline</fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:title text="Hypothesis">Hypothesis</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:blockquote>
                  <html:p>Embedding deep provenance tracking, reversible execution and mergeable histories directly into an interactive programming environment (a POSIX-like shell) greatly decreases the gap between exploratory scientific work and reproducible, publishable results; all whilst leaving existing workflows intact and being programming language agnostic.</html:p>
                </html:blockquote>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:title text="Contributions">Contributions</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:ul>
                  <html:li>
                    <html:p>POSIX-compatibility: I'm interested in both being POSIX-compatible and thinking about the post-POSIX nature of the shell. But this bolsters claims about not breaking existing workflows and is relatively easy to measure.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>MRDT for Shell Histories: Spoke to <fr:link href="/kc/" title="KC Sivaramakrishnan" uri="https://patrick.sirref.org/kc/" display-uri="kc" type="local">KC</fr:link> about this, I think there is some interesting work here for developing a <html:em>useful</html:em> MRDT for this.</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Easy to use provenance tracing: as simple as searching your shell history!</html:p>
                  </html:li>
                  <html:li>
                    <html:p>OS Design Discussion: Plan9, <html:code>fork/exec</html:code>, void processes, VURL etc.</html:p>
                  </html:li>
                </html:ul>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:title text="Outline">Outline</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:ol>
                  <html:li>
                    <html:p>Introduction: <html:em>Setting the scene: exploratory programming, why a shell, scientific results etc.</html:em></html:p>
                  </html:li>
                  <html:li>
                    <html:p>Background</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Design and Theory</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Implementation</html:p>
                  </html:li>
                  <html:li>
                    <html:p>Evaluation</html:p>
                  </html:li>
                </html:ol>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="false">
              <fr:frontmatter>
                <fr:authors>
                  <fr:author>
                    <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:title text="Repositories">Repositories</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:ul>
                  <html:li>
                    <html:p>
                      <fr:link href="https://tangled.org/patrick.sirref.org/merry" type="external">Shell library</fr:link>
                    </html:p>
                  </html:li>
                  <html:li>
                    <html:p>
                      <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">Shelter</fr:link>
                    </html:p>
                  </html:li>
                </html:ul>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Patrick Ferris/" type="external">Patrick Ferris</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2025</fr:year>
              <fr:month>11</fr:month>
              <fr:day>15</fr:day>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/eio-cap-debugging/</fr:uri>
            <fr:display-uri>eio-cap-debugging</fr:display-uri>
            <fr:route>/eio-cap-debugging/</fr:route>
            <fr:title text="Shelter imports › Eio Debugging "><fr:link href="/weekly-2025-w46/" title="Shelter imports" uri="https://patrick.sirref.org/weekly-2025-w46/" display-uri="weekly-2025-w46" type="local">Shelter imports</fr:link> › Eio Debugging </fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>One of the promises of <fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link>'s capability model is an improved debugging experience. Your program must be designed in such a way as to make resources explicit. If you have a <html:code>load_config</html:code> function, more than likely it will need access to the file-system.</html:p>
            <html:pre class="hilite">
              <html:code>
                <html:span class="ocaml-keyword-other">val</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">load_config</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language">_</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Path</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">t</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-operator">-&gt;</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Config</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">t</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-comment-doc"><![CDATA[(**]]></html:span>
                <html:span class="ocaml-comment-doc"><![CDATA[ [load_config path] loads a configuration from [path].]]></html:span>
                <html:span class="ocaml-comment-doc"><![CDATA[*)]]></html:span>
                <html:span class="ocaml-source">
</html:span>
              </html:code>
            </html:pre>
            <html:p>Once all of your resources are explicit and threaded through your program, it becomes much easier to swap out one resource for another (provided they have the same interface).</html:p>
            <html:p>This week I was trying to get the <fr:link href="https://github.com/quantifyearth/LIFE" type="external">LIFE</fr:link> pipeline running in <fr:link href="/shelter/" title="Shelter" uri="https://patrick.sirref.org/shelter/" display-uri="shelter" type="local">shelter</fr:link>. Part of that involves pulling the <fr:link href="ghcr.io/osgeo/gdal:ubuntu-small-3.11.4" type="external">appropriate geospatial container image</fr:link>, but my code was terrifically broken, failing with what looked to me with a Docker error.</html:p>
            <html:p>With only this clue, I knew that it was probably in the execution of some command in a child process, but which one? To trace this quickly, I could plug in a slightly different instance of the <html:code>_ Eio.Process.mgr</html:code> capability. Essentially unchanged from the one provided by the unix backend except that it would also print to stderr the command it was trying to run!</html:p>
            <html:pre class="hilite">
              <html:code>
                <html:span class="ocaml-keyword">let</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-entity-name-function-binding">debug_process_mgr</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                <html:span class="ocaml-source">mgr</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-storage-type">'a</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">mgr</html:span>
                <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-storage-type">'a</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">mgr</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">    </html:span>
                <html:span class="ocaml-keyword-operator">=</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">  </html:span>
                <html:span class="ocaml-keyword">let</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword">module</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">D</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-operator">=</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-other">struct</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">    </html:span>
                <html:span class="ocaml-keyword-other">type</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">t</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-operator">=</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-support-type">unit</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">    </html:span>
                <html:span class="ocaml-keyword">let</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-entity-name-function-binding">spawn_unix</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-unit"><![CDATA[()]]></html:span>
                <html:span class="ocaml-source"> ~</html:span>
                <html:span class="ocaml-source">sw</html:span>
                <html:span class="ocaml-source"> ?</html:span>
                <html:span class="ocaml-source">cwd</html:span>
                <html:span class="ocaml-source"> ?</html:span>
                <html:span class="ocaml-source">pgid</html:span>
                <html:span class="ocaml-source"> ?</html:span>
                <html:span class="ocaml-source">uid</html:span>
                <html:span class="ocaml-source"> ?</html:span>
                <html:span class="ocaml-source">gid</html:span>
                <html:span class="ocaml-source"> ~</html:span>
                <html:span class="ocaml-source">env</html:span>
                <html:span class="ocaml-source"> ~</html:span>
                <html:span class="ocaml-source">fds</html:span>
                <html:span class="ocaml-source"> ~</html:span>
                <html:span class="ocaml-source">executable</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">args</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-operator">=</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">      </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">traceln</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-string-quoted-double">"</html:span>
                <html:span class="ocaml-string-quoted-double">Spawning subprocess... </html:span>
                <html:span class="ocaml-constant-character-printf"><![CDATA[%a]]></html:span>
                <html:span class="ocaml-string-quoted-double">"</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Fmt</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                <html:span class="ocaml-source">list</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-support-type">string</html:span>
                <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">args</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-separator-terminator punctuation-separator">;</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">      </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">spawn_unix</html:span>
                <html:span class="ocaml-source"> ~</html:span>
                <html:span class="ocaml-source">sw</html:span>
                <html:span class="ocaml-source"> ?</html:span>
                <html:span class="ocaml-source">cwd</html:span>
                <html:span class="ocaml-source"> ?</html:span>
                <html:span class="ocaml-source">pgid</html:span>
                <html:span class="ocaml-source"> ?</html:span>
                <html:span class="ocaml-source">uid</html:span>
                <html:span class="ocaml-source"> ?</html:span>
                <html:span class="ocaml-source">gid</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">mgr</html:span>
                <html:span class="ocaml-source"> ~</html:span>
                <html:span class="ocaml-source">env</html:span>
                <html:span class="ocaml-source"> ~</html:span>
                <html:span class="ocaml-source">fds</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">        ~</html:span>
                <html:span class="ocaml-source">executable</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">args</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">  </html:span>
                <html:span class="ocaml-keyword-other">end</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-other">in</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">  </html:span>
                <html:span class="ocaml-keyword">let</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword">module</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">V</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-operator">=</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Make_mgr</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                <html:span class="ocaml-constant-language-capital-identifier">D</html:span>
                <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-other">in</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">  </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Resource</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">T</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                <html:span class="ocaml-constant-language-unit"><![CDATA[()]]></html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-comma punctuation-separator">,</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Process</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Pi</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">mgr_unix</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                <html:span class="ocaml-keyword-other">module</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">V</html:span>
                <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                <html:span class="ocaml-source">
</html:span>
              </html:code>
            </html:pre>
            <html:p>Whist there is a fair amount of jumping through first-class-module-shaped hoops here, all I am doing is rewrapping an existing "method" to a spawn a unix child process. Then using <fr:link href="https://github.com/ocaml-multicore/eio/pull/823" type="external">this helper function</fr:link>, I can push that into my <fr:link href="https://patrick.sirref.org/standard environment/" type="external">standard environment</fr:link>.</html:p>
            <html:pre class="hilite">
              <html:code>
                <html:span class="ocaml-keyword">let</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-entity-name-function-binding">env</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-operator">=</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">  </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Eio_unix</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Stdenv</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">with_env</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">  ~</html:span>
                <html:span class="ocaml-source">process_mgr</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                <html:span class="ocaml-source">debug_process_mgr</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">env</html:span>
                <html:span class="ocaml-keyword-other">#</html:span>
                <html:span class="ocaml-source">process_mgr</html:span>
                <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-source">  </html:span>
                <html:span class="ocaml-source">env</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-keyword-other">in</html:span>
                <html:span class="ocaml-source">
</html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Shelter</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">main</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">config</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source"><![CDATA[(]]></html:span>
                <html:span class="ocaml-source">env</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-colon punctuation">:</html:span>
                <html:span class="ocaml-keyword-operator">&gt;</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language">_</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-constant-language-capital-identifier">Shelter</html:span>
                <html:span class="ocaml-keyword-other-ocaml punctuation-other-period punctuation-separator">.</html:span>
                <html:span class="ocaml-source">env</html:span>
                <html:span class="ocaml-source"><![CDATA[)]]></html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">dir</html:span>
                <html:span class="ocaml-source"> </html:span>
                <html:span class="ocaml-source">cmd_file</html:span>
                <html:span class="ocaml-source">
</html:span>
              </html:code>
            </html:pre>
            <html:p>And sure enough I was querying for the Docker user <html:em>before</html:em> pulling the image! I hadn't run into this, as for the last while I have been using <html:code>alpine</html:code> and <html:code>debian</html:code> images that already exists locally.</html:p>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Related">Related</fr:title>
      </fr:frontmatter>
      <fr:mainmatter>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/ryangibb/</fr:uri>
            <fr:display-uri>ryangibb</fr:display-uri>
            <fr:route>/ryangibb/</fr:route>
            <fr:title text="Ryan Gibb">Ryan Gibb</fr:title>
            <fr:meta name="postion">PhD Student and Nix Guru</fr:meta>
            <fr:meta name="external">https://ryan.freumh.org</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Fellow <fr:link href="https://github.com/fn06" type="external">FN06</fr:link> hacker.</html:p>
          </fr:mainmatter>
        </fr:tree>
      </fr:mainmatter>
    </fr:tree>
    <fr:tree show-metadata="false" hidden-when-empty="true">
      <fr:frontmatter>
        <fr:authors />
        <fr:title text="Contributions">Contributions</fr:title>
      </fr:frontmatter>
      <fr:mainmatter />
    </fr:tree>
  </fr:backmatter>
</fr:tree>
