A POSIX Shell in OCaml [weekly-2026-w12]
- March 19, 2026
- Patrick Ferris
Long time, no weekly. Since the start of this year I have been building a POSIX shell in OCaml called msh (with the underlying library called Merry). Merry is available online now.
A POSIX(ish) shell in OCaml
- March 19, 2026
- Patrick Ferris
Merry is a POSIX(ish) in OCaml. It uses Eio alongside Morbig (a static parser for POSIX shell).
Why another (POSIX) shell?
- March 19, 2026
- Patrick Ferris
Shells have been around for a long time. In my research on the notion of metashell I wrote about Louis Pouzin originally coining the term:
Metashells › Louis Pouzin's "SHELL" [pouzin-shell]
- May 19, 2025
- Patrick Ferris
I spent some time reading part of the multics design documentation 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
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.
And then later, when defining the "SHELL".
We may envision a common procedure called automatically by the supervisor whenever a user types in some message at his console, at a time when he has no other process in active execution under console control (presently called command level). This procedure acts as an interface between console messages and subroutine. The purpose of such a procedure is to create a medium of exchange into which one could activate any procedure, if it were called inside of another program. Hereafter, for simplification, we shall refer to that procedure as the "SHELL".
It still surprises how little the undergraduate degree in computer science at Cambridge focuses on writing skills.
I built Shelter exploring the idea of a shell-like interface that allowed users to undo their shell actions (amongst other cool tricks). Unfortunately shell-like is not enough. Shelter cut many corners to masquerade as a shell (e.g. appending env to understand how a command may have altered the execution environment). I felt it was necessary to make Shelter a "SHELL"! To do that, I needed a solid foundation to build on.
msh, the POSIX shell that comes with Merry, is by no means POSIX-complete in terms of features. But it is my daily driver at this point. It includes a pure OCaml rewrite of linenoise (a small, self-contained alternative to the venerable readline) called bruit.
If you have docker installed on your machine, you can take it for a spin today:
docker run -it --rm patrickferris/msh
The patrickferris/msh docker image is just for trying it out. It is based on the OCaml 5.3 alpine image.
Alternatively, you can build msh from source and have it available in your opam switch.
opam pin git+https://tangled.org/patrick.sirref.org/merry
There are many small paper cuts left to patch over, but most of it is porcelain (e.g. ctrl+left-arrow for moving in bruit). Unfortunately, these are the kinds of things that you will immediately stumble upon.
What makes Merry different?
- March 19, 2026
- Patrick Ferris
Nothing.
Merry 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 actually use... is pretty much all of it. Every possible redirection, variable expansion, shell built-in and compound command make some appearance. Not to mention the non-POSIX bits of shell we all take for granted (e.g. &>-redirection).
Merry and msh are useable. You will most likely find bugs if you use them. If, when using msh, you find something obscure happening you can enable debug mode either my setting the variable MSH_DEBUG or by invoking msh with -v -v.
What's next?
- March 19, 2026
- Patrick Ferris
It is soon time to combine Shelter and Merry into the time-travelling, POSIX-ish shell that I have been trying to build since I first started working on Shelter.
For this to be successful, I need Merry to be able to pass plenty of tests and right now that involves trying to install plenty of packages using tools like apk and apt.
Shell MRDT
- March 19, 2026
- Patrick Ferris
What I am particularly interested in reasoning about, is the execution context in Merry. 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.
This was, in terms of Shelter, the missing piece for truly building some kind of MRDT across shell sessions.
TIFF in OCaml
- March 19, 2026
- Patrick Ferris
I picked up from the excellent Outreachy work of Tambe Salome in getting write-support in ocaml-tiff. We are getting closer to the kind of API I envisaged in this latest round of refinement and review.
let ( / ) = Eio.Path.( / )
let checkerboard ~size =
let v = Nx.zeros Nx.uint8 [| size; size |] in
for row = 0 to size - 1 do
for col = 0 to size - 1 do
if (row + col) mod 2 = 0 then Nx.set_item [ row; col ] 254 v
done
done;
Nx.to_bigarray v
let () =
Eio_posix.run @@ fun env ->
Tiff_eio.with_open_out (env#cwd / "example.tiff") @@ fun w ->
let tif = Tiff.make (checkerboard ~size:256) in
Tiff.to_file tif w

I have also been extremely pleased to see further external collaborators appearing: