<?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: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><![CDATA[ (with the underlying library called]]><html:code>Merry</html:code><![CDATA[).]]> <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"><![CDATA[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><![CDATA[ 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><![CDATA[ (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?"><![CDATA[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 <![CDATA[no other process in active execution under console control (presently called]]> <![CDATA[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><![CDATA[ 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 <![CDATA[shell (e.g. appending]]><html:code>env</html:code> to understand how a command may have altered the <![CDATA[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> <![CDATA[(a small, self-contained alternative to the venerable]]><html:code>readline</html:code><![CDATA[) 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 <![CDATA[(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><![CDATA[). 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 <![CDATA[granted (e.g.]]><html:code>&amp;&gt;</html:code><![CDATA[-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: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 show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors>
              <fr:author>
                <fr:link href="https://patrick.sirref.org/Louis Pouzin/" type="external">Louis Pouzin</fr:link>
              </fr:author>
            </fr:authors>
            <fr:date>
              <fr:year>2013</fr:year>
            </fr:date>
            <fr:uri>https://patrick.sirref.org/pouzin-shell-2013/</fr:uri>
            <fr:display-uri>pouzin-shell-2013</fr:display-uri>
            <fr:route>/pouzin-shell-2013/</fr:route>
            <fr:title text="The Origin of the Shell">The Origin of the Shell</fr:title>
            <fr:taxon>Reference</fr:taxon>
            <fr:meta name="external">https://people.csail.mit.edu/saltzer/Multics/Multics-Documents/MDN/MDN-4.pdf</fr:meta>
            <fr:meta name="journal">Multics Documents</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/Louis Pouzin/" type="external">Louis Pouzin</fr:link>
                  </fr:author>
                </fr:authors>
                <fr:date>
                  <fr:year>2013</fr:year>
                </fr:date>
                <fr:title text="Abstract">Abstract</fr:title>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>How RUNCOM was created for CTSS and the shell was designed for Multics by Louis Pouzin.</html:p>
              </fr:mainmatter>
            </fr:tree>
          </fr:mainmatter>
        </fr:tree>
      </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 show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/weeklies-2026/</fr:uri>
            <fr:display-uri>weeklies-2026</fr:display-uri>
            <fr:route>/weeklies-2026/</fr:route>
            <fr:title text="Patrick Ferris' Weeklies › 2026 "><fr:link href="/weeklies/" title="Patrick Ferris' Weeklies" uri="https://patrick.sirref.org/weeklies/" display-uri="weeklies" type="local">Patrick Ferris' Weeklies</fr:link> › 2026 </fr:title>
          </fr:frontmatter>
          <fr:mainmatter>
            <fr:tree show-metadata="false" 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 <![CDATA[compiler (currently in its]]><html:code>alpha3</html:code><![CDATA[ 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><![CDATA[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><![CDATA[ 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 <![CDATA[process with a new one (e.g.]]><html:code>exec vim</html:code><![CDATA[). 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><![CDATA[ (h/t]]><fr:link href="/anilmadhavapeddy/" title="Anil Madhavapeddy" uri="https://patrick.sirref.org/anilmadhavapeddy/" display-uri="anilmadhavapeddy" type="local">Anil</fr:link><![CDATA[).]]> 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><![CDATA[ (by redirecting a command's]]> standard output to <html:code>4</html:code> i.e. <html:code>&gt;&amp;4</html:code><![CDATA[) will output to where standard output is]]> <![CDATA[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 <![CDATA[before being reused; the close is performed silently (i.e., any errors during]]> <![CDATA[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><![CDATA[ and will likely grind Eio to a halt (or an]]> <html:code>assert false</html:code><![CDATA[). 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="false" 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><![CDATA[ (with the underlying library called]]><html:code>Merry</html:code><![CDATA[).]]> <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"><![CDATA[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><![CDATA[ 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><![CDATA[ (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?"><![CDATA[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 <![CDATA[no other process in active execution under console control (presently called]]> <![CDATA[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><![CDATA[ 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 <![CDATA[shell (e.g. appending]]><html:code>env</html:code> to understand how a command may have altered the <![CDATA[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> <![CDATA[(a small, self-contained alternative to the venerable]]><html:code>readline</html:code><![CDATA[) 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 <![CDATA[(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><![CDATA[). 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 <![CDATA[granted (e.g.]]><html:code>&amp;&gt;</html:code><![CDATA[-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:mainmatter>
        </fr:tree>
      </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>
    <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: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/merry/</fr:uri>
            <fr:display-uri>merry</fr:display-uri>
            <fr:route>/merry/</fr:route>
            <fr:title text="Merry">Merry</fr:title>
            <fr:meta name="external">https://tangled.org/patrick.sirref.org/merry</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Merry is a library for building POSIX-ish shells in OCaml. It comes with a <![CDATA[(work-in-progress) POSIX shell written using]]><fr:link href="/eio/" title="Eio" uri="https://patrick.sirref.org/eio/" display-uri="eio" type="local">Eio</fr:link> called <html:code>msh</html:code>.</html:p>
            <html:p>Supporting the full <fr:link href="https://pubs.opengroup.org/onlinepubs/9699919799.2013edition/" type="external">POSIX specification</fr:link> is no easy feat, however, <html:code>msh</html:code> already <fr:link href="https://tangled.org/patrick.sirref.org/merry/tree/main/test" type="external">supports plenty of the more useful bits of the spec</fr:link>.</html:p>
          </fr:mainmatter>
        </fr:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/eio/</fr:uri>
            <fr:display-uri>eio</fr:display-uri>
            <fr:route>/eio/</fr:route>
            <fr:title text="Eio">Eio</fr:title>
            <fr:meta name="external">https://github.com/ocaml-multicore/eio</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:blockquote>
              <html:p>Eio provides an effects-based direct-style IO stack for OCaml 5</html:p>
            </html:blockquote>
          </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/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><![CDATA[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:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/outreachy/</fr:uri>
            <fr:display-uri>outreachy</fr:display-uri>
            <fr:route>/outreachy/</fr:route>
            <fr:title text="Outreachy">Outreachy</fr:title>
            <fr:taxon>Project</fr:taxon>
            <fr:meta name="external">https://www.outreachy.org/</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:blockquote>
              <html:p>Outreachy provides internships in open source and open science. Outreachy provides internships to people subject to systemic bias and impacted by underrepresentation in the technical industry where they are living.</html:p>
            </html:blockquote>
            <html:p>I am one of the coordinators for the <html:em>OCaml community</html:em> for Outreachy. I have also mentored multiple three-month internships for the community.</html:p>
            <html:hr />
            <fr:tree show-metadata="true" expanded="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:tree show-metadata="true" expanded="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2022</fr:year>
                  <fr:month>12</fr:month>
                  <fr:day>1</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/topojson-0001/</fr:uri>
                <fr:display-uri>topojson-0001</fr:display-uri>
                <fr:route>/topojson-0001/</fr:route>
                <fr:title text="Implement a non-blocking, streaming codec for TopoJSON">Implement a non-blocking, streaming codec for TopoJSON</fr:title>
                <fr:meta name="external">https://github.com/geocaml/ocaml-geojson</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>GeoJSON is a JSON standardised format for handling simple geographical data. One common use of GeoJSON is to add map overlays such as with the popular JavaScript library leaflet. One issue with GeoJSON is redundant data, for example when two polygons share boundaries ideally only one would contain the full data about the boundary, however, with GeoJSON the data is duplicated.</html:p>
                <html:p>TopoJSON is an extension to GeoJSON to encode topology. This allows for redundant data to be removed and file sizes to be greatly reduced. This is often very desirable especially when working with data in the browser. In a previous Outreachy internship a new OCaml library was implemented to provide an OCaml library for TopoJSON, this project will build on this adding more functionality to the library and providing a non-blocking, streaming codec version similar to the geojsone library.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="true" expanded="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2022</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>1</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/topojson-0002/</fr:uri>
                <fr:display-uri>topojson-0002</fr:display-uri>
                <fr:route>/topojson-0002/</fr:route>
                <fr:title text="Extend OCaml's GeoJSON library to support TopoJSON">Extend OCaml's GeoJSON library to support TopoJSON</fr:title>
                <fr:meta name="external">https://github.com/geocaml/ocaml-geojson</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>GeoJSON is a JSON standardised format for handling simple geographical data. One common use of GeoJSON is to add map overlays such as with the popular JavaScript library leaflet. One issue with GeoJSON is redundant data, for example when two polygons share boundaries ideally only one would contain the full data about the boundary, however, with GeoJSON the data is duplicated.</html:p>
                <html:p>TopoJSON is an extension to GeoJSON to encode topology. This allows for redundant data to be removed and file sizes to be greatly reduced. This is often very desirable especially when working with data in the browser. In a previous Outreachy internship a new OCaml library was implemented to provide an OCaml library for TopoJSON, this project will build on this adding more functionality to the library and providing a non-blocking, streaming codec version similar to the geojsone library.</html:p>
              </fr:mainmatter>
            </fr:tree>
            <fr:tree show-metadata="true" expanded="false">
              <fr:frontmatter>
                <fr:authors />
                <fr:date>
                  <fr:year>2021</fr:year>
                  <fr:month>6</fr:month>
                  <fr:day>1</fr:day>
                </fr:date>
                <fr:uri>https://patrick.sirref.org/ocamlorg-0001/</fr:uri>
                <fr:display-uri>ocamlorg-0001</fr:display-uri>
                <fr:route>/ocamlorg-0001/</fr:route>
                <fr:title text="Improve the ocaml.org Website">Improve the ocaml.org Website</fr:title>
                <fr:meta name="external">https://ocaml.org</fr:meta>
              </fr:frontmatter>
              <fr:mainmatter>
                <html:p>OCaml.org is the main website for OCaml, a functional, typed, high-level programming language. This project revolves around improving the website on multiple different fronts including: layout, accessibility and content.</html:p>
                <html:p>Because a lot of the content of the website is about OCaml and the website itself is written in OCaml, this would be a great opportunity for interns to learn the language and functional programming concepts.</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: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>[<html:span class="ansi32">main</html:span>#<html:span class="ansi35">bbd691a</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; @ session exp-1
<html:span class="ansi33">shelter</html:span>[<html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">bbd691a</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; echo world &gt;&gt; hello.txt
<html:span class="ansi33">shelter</html:span>[<html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">dd5bab8</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; @ session main
<html:span class="ansi33">shelter</html:span>[<html:span class="ansi32">main</html:span>#<html:span class="ansi35">bbd691a</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; echo "to the" &gt;&gt; hello.txt
<html:span class="ansi33">shelter</html:span>[<html:span class="ansi32">main</html:span>#<html:span class="ansi35">b9abef4</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; cat hello.txt
hello
to the
<html:span class="ansi33">shelter</html:span>[<html:span class="ansi32">main</html:span>#<html:span class="ansi35">d1c1728</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; @ session exp-1
<html:span class="ansi33">shelter</html:span>[<html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">dd5bab8</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; @ replay main
<html:span class="ansi33">shelter</html:span>[<html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">df1b4e1</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; cat hello.txt
hello
to the
world
<html:span class="ansi33">shelter</html:span>[<html:span class="ansi32">exp-1</html:span>#<html:span class="ansi35">67162b7</html:span>] : { mode: <html:span class="ansi31">rw</html:span> }&gt; 
</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. <![CDATA[It points to the head commit of the branch it came from (]]><html:code>git checkout -b exp-1</html:code><![CDATA[).]]></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><![CDATA[ of the two branches and re-applies the commits from your current branch (here]]><html:code>exp-1</html:code><![CDATA[) onto the head of the target branch (here]]><html:code>main</html:code><![CDATA[).]]></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>. <![CDATA[It uses the similar ideas, like snapshotting filesystems (e.g.]]><fr:link href="https://github.com/patricoferris/ocaml-zfs" type="external">ZFS</fr:link><![CDATA[) and Linux namespaces (e.g.]]><fr:link href="https://github.com/quantifyearth/void" type="external">Void</fr:link><![CDATA[).]]> 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:tree>
        <fr:tree show-metadata="true" expanded="false" toc="false" numbered="false">
          <fr:frontmatter>
            <fr:authors />
            <fr:uri>https://patrick.sirref.org/ocaml-tiff/</fr:uri>
            <fr:display-uri>ocaml-tiff</fr:display-uri>
            <fr:route>/ocaml-tiff/</fr:route>
            <fr:title text="ocaml-tiff">ocaml-tiff</fr:title>
            <fr:meta name="external">https://github.com/geocaml/ocaml-tiff</fr:meta>
          </fr:frontmatter>
          <fr:mainmatter>
            <html:p>Part of the <fr:link href="/geocaml/" title="Geocaml" uri="https://patrick.sirref.org/geocaml/" display-uri="geocaml" type="local">geocaml</fr:link> suite of geospatial libraries for OCaml.</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>
