SUNDAY, OCTOBER 11, 2026|No. 18261
Technology · Software Development

Unikernels Emerge as More Accessible for Modern Development

Once considered complex, unikernels are now being discussed as more implementable, with AI playing a role in simplifying their adoption.

A representation of code and interconnected systems, symbolizing software development and cloud computing.
A representation of code and interconnected systems, symbolizing software development and cloud computing. · Photo by Growtika on Unsplash
1 sources
Pipeline ingest
3 reads
Positive / Neutral / Negative
0 countries
Related coverage

Justin Cormack, who worked on MirageOS and Unikernel Systems, has observed a resurgence in interest in unikernels. He is hosting a series of discussions on the topic in his newsletter, and I was the first guest. We discussed Mirage, Orleans, Haskell, Nix, Cursed, and more.

Unikernels in 2026: Justin Cormack in conversation with Geoffrey Huntley - YouTube

Unikernels in 2026: Justin Cormack in conversation with Geoffrey Huntley

Geoffrey Huntley

Here's the summary, properly written, with chapter links at the bottom if you want to jump to a specific part of the conversation. Justin's edited transcript is available at Ignore Previous Directions.

Unikernels used to be difficult. Now, with AI, they are not.

What a Unikernel Is, and Why They Were Difficult

I first encountered unikernels around 2015. My team, composed of Haskellers, had delved deeply into functional programming. Where there are Haskellers, there are OCaml programmers, and from there, one discovers MirageOS. It was a great concept. I experimented with it back then.

A unikernel is essentially an application that is the operating system. There is no userland. If you need a web server, DNS, or email functionality, you cannot fork or spawn anything. These capabilities must be implemented as libraries within your application.

That was the challenge. Justin recalls the difficulties well: when they were developing Mirage, they had a TCP stack and an HTTPS stack, but there was a significant lack of storage support. They had to extract drivers from NetBSD to run them in userspace. It was a challenging endeavor back then.

Our industry is often characterized by dogma. Nix is considered difficult. Bazel is difficult. Unikernels are difficult. Yes, they were. These complex concepts are now embedded within model weights. All that's required is to prompt for them and, mentally, shed the belief that they are inherently difficult.

The Operating System is Design Debt

Every application that is not a unikernel was built with the assumption of an application layer residing above an operating system. Why do we even have an operating system? Because forty years ago, there was a human operator. I have experience with IBM 5250, AIX, Solaris, and mainframes. The multi-user operating system exists because a person interacted with it directly, and then the application was placed on top.

I view this as design debt, and here's why it's critical now. Applications are frequently compromised. They were being compromised even before AI. An attacker compromises the userland application and gains a shell. This shell acts as a privileged butler service for data exfiltration.

With a unikernel, the attack surface is significantly reduced. If the required functionality is not present in the application (the operating system), the attacker is thwarted. There is no subsequent step for them.

Justin raised a valid point: attack-surface reduction is often poorly understood. While you can remove the shell from a Linux container, most Linux environments still retain something akin to an interpreter. It's possible to execute a new program without a writable filesystem. Memory safety and exploitability through gadgets remain concerns.

All of that is true. But consider our efforts over the past twenty-six years. The earliest advice I recall from the SunOS and cgi-bin era was "don't put the compiler on production." Then came build containers and production containers. Subsequently, Chainguard emerged. We continuously reduce the attack surface, rather than fundamentally eliminating it.

And this is the crucial point that is often missed: if there is no shell and no interpreter, there is nothing within the model weights that can execute subsequent actions. This transforms a drive-by attack (where exploiting a common framework's RCE grants shell access, and the model weights understand how to utilize shell access) into a targeted attack requiring access to your source code.

You Can Now Port Missing Libraries

The classic objection: your unikernel needs to interact with Stripe, but OCaml lacks a Stripe library. Before AI, you would sigh and write it yourself. Now? Run a loop to port the Go library to OCaml. Voilà: Stripe in a unikernel.

Justin shared a similar example. He was creating minimal Linux OS images for appliances, which is a step towards unikernels since only one application runs as PID 1. He needed to create an XFS filesystem. Instead of incorporating xfsprogs and all its dependencies, he used an agent to generate mkfs.xfs in Rust, producing byte-for-byte identical output, with every flag correctly interpreted. It reverse-engineered the on-disk formats incrementally, with tests across various block sizes. This process took a few hours.

This approach is effective because the original tool serves as a definitive reference. Generate filesystems of different sizes using both implementations and compare them. Port the tests. Automate the process.

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 Huntley

Storage was another significant gap. Most modern workloads are cloud-oriented, even on-premises. Therefore, adopt the turbopuffer approach: use S3 as your primary, infinitely scalable storage, with a local NVMe block cache and an LRU (or your preferred caching algorithm) for frequently accessed data. Justin is also a strong proponent of "S3 for everything." As long as latency is not a critical constraint, you gain infinite storage with multi-user access, and you can build everything upon it.

Nix Machine Tests and Overlays

Justin had also been experimenting with Nix and was surprised that the first time he asked an agent to prototype an OS, it included all the tests within the flakes.

The Nix language itself is cumbersome. Nixpkgs, however, is excellent. NixOS machine tests are remarkable: they allow you to write tests that deploy a fleet of machines and verify the interaction between your network rules and your application. This is a feature that many are unaware of.

And when something upstream is broken, or there's a supply chain issue with your dependencies, it can be resolved with an overlay.

The world hasn't yet realized that you can literally fix everything with a Nix overlay

Patch the world.

Geoffrey HuntleyGeoffrey Huntley

If you need to involve a human, also known as "Dear Maintainer," who might be on vacation or may have abandoned the project, and wait for hours or even days, that is not AGI.

We are developing recursive products here. Agents require the capability to modify the world as a first-party source, not as third-party bundled binaries. We are returning to the concept of the contrib folder and Unix patches.

If You Care About Security, You Have Two Choices

Justin inquired about what unikernels still require for broader adoption. Honestly, it's this: we have raised two generations of developers who are unaware of their existence.

If you are deeply concerned about security, there are essentially two options:

  1. You are launching satellites into space, in which case you should probably use seL4, a formally verified operating system. (I still harbor some resentment about the Australian government disbanding that team.)
  2. Everyone else should seriously consider unikernels. Stop attempting to harden systems that are highly vulnerable. Instead, invert the approach and design from the ground up.

The other common criticism is that many early unikernel designs ran everything at a single privilege level: your application shared the same ring as the OS. In 2026, this can be resolved with a prompt if ring separation is desired. It is certainly more secure than relying on the correct configuration of your systemd cgroup.

Consider the significant amount of time enterprises dedicate to patching systems every time a new vulnerability is discovered in Linux. Upstream now expects you to patch your kernel weekly. During the week of our recording, someone exploited KVM (essentially Firecracker, the core primitive we believed provided robust sandboxing) and was awarded $50,000 by Vercel and several other vendors. This is a relatively small sum for a vulnerability that could compromise every managed cloud provider globally.

Spaceleans: A Distributed Unikernel Operating System

Approximately seven months ago, I thoroughly investigated unikernels to validate my understanding. I showed Justin my Mirage folder, which contains all the functionality I needed to implement.

  • There was no mechanism for a unikernel fleet to maintain synchronized time, so I ported an NTP client from another language. Subsequently, I developed an NTP server based on RADclock, incorporating ideas from how TigerBeetle handles time: utilizing multiple clock sources, 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 managing back pressure over HTTP, along with some PPX metaprogramming for added functionality.
  • A PII wrapper at the logging boundary, ensuring that secrets and PII never leak through the logging subsystem. Every project should incorporate this. It is pluggable; simply use a functor.

And then the most unconventional creation, which I had never shown anyone before: Spaceleans, a port of Microsoft Orleans to OCaml, running as a unikernel.

Orleans is a distributed actor system with transaction support. It allows you to combine multiple physical machines into a single addressable heap. An actor always exists: await GetCustomer(). If it's not in memory, it's rehydrated from a pluggable storage provider. You can consolidate your n-tier architecture into actors and disregard whether something resides on machine A, B, C, or D. The runtime manages this as an infrastructure primitive.

So, in a peculiar way, I constructed a distributed unikernel operating system out of actors, with a filesystem on top. Justin described it as Erlang-esque, and he is correct. I accomplished all of this in a week. I will likely never release it, but it disproved the notion that unikernels are difficult.

Sampling History

Being older allows one to draw from historical knowledge, much like an experienced DJ such as Carl Cox, who has been in the scene long enough to incorporate past repertoire into current sets. All of these concepts existed in the eighties. The models have studied the relevant papers. They have been trained on TAPL and the most advanced type theory.

The missing elements are people's curiosity and ambition to undertake these unconventional tasks, and the awareness that previous works exist from which to draw inspiration.

How do we encourage people to try these technologies? We simply do it. If you possess a highly efficient and secure advanced system, congratulations; you have an advantage. Create compelling projects, attract curious newcomers, mentor them, and foster growth. It's the same approach as always.

Meanwhile, others will be attempting to secure their Ruby on Rails applications and manage AWS with a large team of AWS-certified engineers, when two individuals with Nix and Hetzner could achieve the same result. Ultimately, it comes down to cost. More powerful tools are more efficient, and efficiency prevails, especially as AI reduces profit margins.

OCaml, Rust, Haskell, and Back Pressure

Has OCaml's time come again? It remains strong. A particular trading firm is utilizing it effectively. When I spoke with Yaron at the beginning of the year, I asked him if OxCaml exists to ensure their language extensions are incorporated into training data and elevate the entire company. He responded with a knowing, "no comment" smile.

For agents, OCaml is an excellent choice. Functors between modules are elegant. The .mli files, which provide typed headers explaining module functionality, offer highly efficient context for agents. opam and Dune are genuinely good. Hindley–Milner type system. And compilation times are fast. I see no reason to use F# these days.

Justin has primarily been writing Rust, and agents are adept at working with Rust. However, compile time is the cost of back pressure. LLMs hallucinate, and when compilation is slow, each hallucination is costly due to fewer attempts per minute.

Haskell's type system is powerful, and models handle it exceptionally well. However, I am hesitant to use it in production: a space leak can reside in the runtime state and only manifest in production. Justin pointed out that the linear-type concepts in Rust originated from Haskell papers attempting to address precisely that issue. Then there's Zig's approach: allocate everything upfront and never allocate again, a technique employed by game developers in the eighties and nineties. It's challenging to instruct an agent to implement this in Rust, as constant-memory programs are not part of its training data.

I believe dependent types represent the future for next-generation languages. Anything that allows for more codification within the type system provides greater back pressure. You might not be surprised to learn that I have a fork of the Rust toolchain with dependent types. It enables new possibilities.

Languages for Agents, and What Cursed Taught Me

The pace of language development has been constrained by how quickly humans can learn new concepts. Operator chaining is essentially syntactic sugar for human readability. If agents are writing the code, we can leverage forty years of academic PLT research, provided one knows how to sample it.

The industry established the principle of "do not make breaking changes" after the transition from Python 2 to 3. Justin was aware of companies that spent years migrating hundreds of people. I believe this rule is no longer applicable. Ship a skill pack with the breaking change and allow agents to perform automatic migrations.

Justin asked about the actual cost of making a new language successful today. Go was the last language a company invested significant resources in, and it took a considerable amount of time. I can answer that.

I ran Claude in a loop for three months, and it created a GenZ programming language called Cursed

It's the only compiled language that lets you code with sus, slay and vibes.

Geoffrey HuntleyGeoffrey Huntley

Cursed was developed using Sonnet 3.5 and 3.7, with a deliberately underspecified prompt, and run in a loop for three months. I began in C (insufficient back pressure; I spent too much time debugging with Valgrind as the agent corrupted its own updates), then moved to Rust, and finally Zig. Choosing Zig was a mistake; I would have succeeded if I had stayed with Rust. The cost was approximately US$6,000, and I repeated the process three times.

Now for the crucial part, the aspect that still concerns me. If the context window is allocated correctly—using a lookup table for lexical structure and grammar—the model can program in a language not present in its weights. It's a brute-force and inefficient method, but it works.

Consider T-diagrams (tombstone diagrams). Lock down your grammar and lexical structure, achieve a stage-two self-hosting compiler, ship a sensible standard library, and initiate the next training run. From there, you can rapidly achieve a Roslyn-style self-hosted compiler with language services. Justin inquired whether fine-tuning an open model would aid in bootstrapping such a language. It is not necessary.

This was true a year and a half ago with much less capable models. It will only take one programming language designer to fully commit to using advanced models to astound the world.

What Next

As the pub was closing, Justin asked what was on my mind. If you haven't read my latest post, please do. If you manage people, create the space and time for them to experiment now, because within six months, leadership will expect you to place individuals on a vitality curve.

If your team is too busy doing their 'normal job' to experiment with AI, you're preparing them to be replaced

AI use is now mandatory for employability.

Geoffrey HuntleyGeoffrey Huntley

Yes, the training data was sourced from the commons. I dislike that, and I understand it. However, you trade time and skill for money; employers have minimum standards, and those standards have evolved more rapidly than ever before in our industry. Be curious, learn how to build an agent, and create remarkable things. We are in a renaissance.

It's a time-compression device. The more experience you possess, the more you can draw upon. Not everything is released; some of what I demonstrated to Justin may never see the light of day. I use these projects as practice exercises and redo them as models improve.

But if you want to build something secure, seriously consider unikernels.

Chapters

  • 0:21 — Discovering Unikernels: Haskell to OCaml to Mirage
  • 0:55 — What a Unikernel Is, and Why It Was Hard
  • 2:45 — "Hard" Was Past Tense
  • 3:33 — Why Do We Have an Operating System?
  • 4:17 — The Shell is a Butler Service for Exfiltration
  • 5:12 — Attack Surface Reduction is Fuzzy
  • 7:26 — Don't Put the Compiler on Production
  • 9:13 — Porting Stripe into a Unikernel
  • 9:54 — Minimal Linux and mkfs.xfs in Rust
  • 12:22 — S3 for Everything
  • 13:48 — Nix, Machine Tests and Overlays
  • 15:28 — Tool-Calling a Human is Not AGI
  • 15:53 — seL4 or Unikernels
  • 16:56 — Privilege Rings
  • 18:24 — Weekly Kernel Patches and the KVM Escape
  • 19:38 — Demo: The Mirage Folder, NTP and Time
  • 22:05 — Spaceleans: Orleans in OCaml as a Unikernel
  • 25:31 — Sampling History
  • 26:52 — How to Get People to Try This: Just Do It
  • 28:57 — OCaml and OxCaml
  • 31:45 — Rust Compile Times and Back Pressure
  • 33:06 — Haskell, Space Leaks and Dependent Types
  • 35:13 — Memory Strategies: Rust, Zig and Game Devs
  • 36:10 — Languages Designed for Agents
  • 37:41 — Breaking Changes and Skill Packs
  • 38:53 — Cursed
  • 42:36 — What Cursed Taught Me
  • 46:47 — What's Next: AI Use is Mandatory

Stay curious.

P.P.S. Don't Miss Out on Free Lifetime Access

Join thousands receiving premium insights weekly. Subscribe now and you'll never pay—even when I start charging new subscribers. This free-for-life offer won't last forever.

Subscribe to Newsletter

You Might Also Like...

if your team is too busy doing their 'normal job' to experiment with AI, you're preparing them to be replaced

--help on your CLI is all you need for LLM context until you don't.

to Kodak yourself out of business

the world hasn’t figured out yet that you can literally just fix everything with a Nix overlay

PAN's pipeline reviewed approximately 1 open sources for this article. No human editor reviewed this article before publication.

Related Reads

Show on timeline →

Earlier on PAN

More in Technology →