Pangram verdict · v3.3
We believe that this entire text is human-written.
AI likelihood · overall
HumanArticle text · 1,654 words · 1 segments analyzed
Justin Cormack, who worked on MirageOS and Unikernel Systems back in the day, has been noticing what I've been noticing: people are discovering (or rediscovering) unikernels again. He's running a series of conversations on the topic for his newsletter, and I was first up. He emailed me, and five minutes later I was talking to him from the pub with a stein of beer in hand. We went deep on Mirage, Orleans, Haskell, Nix, Cursed and a whole lot more.Here's the gist, written up properly, with chapter links at the bottom if you want to jump to a specific part of the conversation. Justin's edited transcript is over at Ignore Previous Directions.Unikernels were hard. Key word: were. Now we have AI.what a unikernel is, and why they were hardI first ran into unikernels around 2015. I'd staffed up a team of Haskellers and gone pretty deep on functional programming. Where there are Haskellers, there are OCaml programmers, and from there you find MirageOS. Great idea. I played with it back then.A unikernel is the idea that your application is the operating system. There's no userland. If you want a web server, DNS, or to send an email, there's nothing you can fork or spawn. You have to write those things as libraries in your application.That was the friction. Justin remembers it well: when they were building Mirage, they had a TCP stack and an HTTPS stack, but there was almost nothing for storage. They were pulling drivers out of NetBSD because they could run them in userspace. It was hard back then.There's a lot of dogma in our industry. Nix is hard. Bazel is hard. Unikernels are hard. Yes, they were. These hard concepts are now in the model weights. All you've got to do is prompt for them and, cognitively, get rid of the dogma that they're hard.the operating system is design debtEvery application that isn't a unikernel was built on the assumption that there's an application, and then there's an operating system underneath. Why do we even have an operating system? Because forty years ago there was a human operator. I've done IBM 5250, AIX, Solaris, and mainframes. The multi-user operating system exists because a person sat in front of it, and then we put the application on top.I consider that design debt, and here's why it matters right now. Applications get popped. They were getting popped before AI. Someone pops the userland application and gets a shell. That shell is a VIP butler service for exfiltration.With a unikernel, the attack surface is much smaller. If the functionality isn't in the application (the operating system), then the attacker is screwed. There's no next hop.Justin pushed back here, and fairly. Attack-surface reduction is something people are very fuzzy about. You can remove the shell from a Linux container, but almost every Linux environment still has something that's effectively an interpreter. You can execute a new program without a writable filesystem. You've still got memory safety and gadgets to worry about.All true. But look at what we've been doing for twenty-six years. The earliest adage I remember from the SunOS and cgi-bin days was "don't put the compiler on production." Then came build containers and production containers. Then Chainguard. We keep chipping away at the attack surface, instead of going in the opposite direction and ensuring there is no attack surface.And this is the bit people miss: if there's no shell and no interpreter, there's nothing in the model weights that knows what to do next. That turns a drive-by (pick your framework's RCE of the week and you've got a shell, and the model weights know what to do with shell access) into a targeted attack that needs your source code.you can just port the missing libraries nowThe classic objection: your unikernel needs to talk to Stripe, and OCaml doesn't have a Stripe library. Before AI you'd sigh and write it. Now? Run a loop to port the Go library to OCaml. Here you go: Stripe in a unikernel.Justin had a great example of the same thing. He'd been building minimal Linux OS images for appliances, which is halfway to a unikernel anyway, since you're only running one application as PID 1. He needed to make an XFS filesystem. Rather than drag in xfsprogs and everything it brings with it, he sat down with an agent and had it write mkfs.xfs in Rust, producing byte-for-byte identical output, with every flag interpreted. It reverse-engineered the on-disk formats one by one, with tests across block sizes. It took a few hours.That works because the original tool is a golden oracle. Generate filesystems at different sizes with both implementations and diff them. Port the tests across. Automate it.porting software has been trivial for a while now. here's how you do it.If you have an oracle, porting is a loop.Geoffrey HuntleyGeoffrey HuntleyStorage was the other big gap. Most workloads these days are cloud-shaped, even on-prem, so take the turbopuffer approach: S3 as your primary, infinitely growable storage, with a local NVMe block cache and an LRU (or whatever caching algorithm you like) for the hot bits. Justin is a massive "S3 for everything" fan too. As long as latency isn't the constraint, you get infinite storage with multi-user access, and you can build everything on it.nix machine tests and overlaysJustin had been experimenting with Nix too, and was surprised that the first time he got an agent to prototype an OS, it built all the tests into flakes.Nix the language sucks. Nixpkgs is great. NixOS machine tests are the bee's knees: you write a test that spins up a fleet of machines and exercises the interaction between your network rules and your application. It's the thing people don't know about.And when something upstream is broken, or there's a supply chain problem in your dependencies, that's just an overlay.the world hasn't figured out yet that you can literally just fix everything with a Nix overlayPatch the world.Geoffrey HuntleyGeoffrey HuntleyIf you have to tool-call a human, also known as "Dear Maintainer", who might be on holiday or might have abandoned the project, and wait a day, two days, or even five minutes, that's not AGI.We're building recursive products here. Agents need the ability to modify the world as first-party source, not as third-party bundled binaries. We're going back to the contrib folder and Unix patches.if you care about security, you have two choicesJustin asked what unikernels still need for people to discover them. Honestly, it's this. We've raised two generations of developers who don't even know they're a thing.If you deeply care about security, there are really two choices:You're sending satellites into space, and you should probably use seL4, a formally verified operating system. (I'm still a bit salty about the Australian government disbanding that team.)Everyone else should seriously consider unikernels. Stop trying to harden something that is very hackable. Invert it and design from the other direction.The other classic criticism is that many early unikernel designs ran everything at a single privilege level: your application in the same ring as the OS. In 2026, that's a prompt away from being fixed if you want ring separation. It's certainly more secure than praying to god your systemd cgroup configuration is right.Think about how much time enterprises spend patching the world every time something new drops in Linux. Upstream now expects you to patch your kernel weekly. The week we recorded, someone popped KVM (essentially Firecracker, the core primitive we all thought was good sandboxing) and collected $50,000 from Vercel and a few other vendors. That is not much money for something that could root every managed cloud provider in the world.spaceleans: a distributed unikernel operating systemAbout seven months ago, I went deep on unikernels to check whether my mental model was right. I showed Justin my Mirage folder, which holds all the functionality I needed to add.There was no way for a unikernel fleet to keep time, so I took an NTP client from another language and ported it. Then I built an NTP server based on RADclock and borrowed ideas from how TigerBeetle handles time: not one clock source but many, packaged as a library.Network stack, DNS, HTTP clients and servers, structured logging, OTel, Anthropic and OpenAI clients, and payments via Airwallex.A generic retry library for handling back pressure over HTTP, plus some PPX metaprogramming for fun.A PII wrapper at the logging boundary, so secrets and PII never leak through the logging subsystem. Every project should have one. It's pluggable; just use a functor.And then the most cooked thing, which I'd never shown anyone before: Spaceleans, Microsoft Orleans ported to OCaml, running as a unikernel.Orleans is a distributed actor system with transactions. You take many physical machines and merge them into one addressable heap. An actor always exists: await GetCustomer(), and if it isn't in memory, it gets rehydrated from a pluggable storage provider. You collapse your n-tier architecture into actors and stop caring whether something lives on machine A, B, C or D. The runtime handles it as an infrastructure primitive.So in a weird sense, I built a distributed unikernel operating system out of actors, with a filesystem on top. Justin called it Erlang-esque, and he's right. I did all of it in a week. I'll probably never release it, but it falsified the idea that unikernels are hard.sampling historyBeing a little older means you can sample history, like an experienced DJ such as Carl Cox, who's been in the scene long enough to pull from previous repertoire and bring it forward. All of these ideas existed in the eighties. The models have read the papers. They've got TAPL and the most advanced type theory in their training data.The thing that's lacking is people's curiosity and ambition to do these unhinged things, and the knowledge that previous records exist that can be sampled from.How do we get people to try this stuff? We just do it. If