I don't plan to start this project for several years, probably 2030 at the absolute earliest, but the fundamental premise is to move a lot of software composition decisions to the end user's discretion, rather than the software author.  Consider this document incomplete until it states otherwise.
## Flexibility first, performance second

Mercury is named primarily after mercury _the metal_, which is liquid at room temperature, allowing it to be arbitrarily reshaped by amateur human hands, and to fit in any odd-shaped vessel or crevice. While the specifics of that flexibility will be fleshed out below, the overall mentality is important to state up front.

The Mercury Microkernel should be able to host an incredible diversity of workloads over an incredible diversity of hardware. From (the high end of) embedded to phones to desktops to servers to supercomputing clusters, by making the core of the project small and easy for volunteers to port, the same architectural foundation can be the starting point of many ecosystems that only partially overlap with each other.

When I say that performance is a secondary concern, I don't mean that speed is deprioritized, I mean that it's deferred. It's okay for things to be slow today, _under the condition that_ I've reserved the space in the design for things to be fast tomorrow.
## Cellular architecture

More fundamental than threads or processes, Mercury has a concept of "cells," which are bits of code that are:

 * Initialized with a set of typed parameters
 * Given a few IPC channels up front, and possibly more later
 * Have their own stack and heap

You can have cells in the same process, or in separate processes. They communicate via channels either way, and don't care whether they're working within a single process or not.

This is how the signature feature of Mercury, **Detachable Drivers**, works: a driver can be compiled once, then used as a server process or within the kernel. This allows drivers to be rapidly iterated, isolated for stability, leaving a minimal trusted base, etc. - the conventional benefits of microkernels - or, as an operator tuning decision, moved into kernel space for performance. Mercury is, to my current knowledge, the only microkernel project designed so that you can operate it as a monolithic kernel.

The IPC channels do not have a type, but they have two widths: bytes per element, and number of elements in the buffer. They operate on ranges claimed and freed by the producer and consumer, not an element at a time. The producer metadata and consumer metadata are on separate cache lines to avoid MESI contention.

Cells make the decision of "should this be a library or a separate program?" late-binding. This means that libraries can have the benefits of separate programs (communicate in serialized formats that can be studied, can replace with functional equivalents, can be upgraded) while still operating in the same process address space.
## Native code

Unlike some other experimental microkernel or unikernel projects, there isn't some designated programming language or bytecode compilation target that software "ought" to be written in. Part of a commitment to simplicity and performance means that, when you need to, you can write in hardware-specific assembly to achieve the latest that AVX has to offer, ensure specific synchronization instructions, or explicit poking at the memory registers of GPIO pins on an ESP-32.

That doesn't mean that you can just run existing binaries built for Linux/OS X/Windows without some kind of compatibility layer. Mercury has its own calling conventions that emphasize asynchronous communication.
## What's a syscall?

Mercury does not have system calls. It has asynchronous message passing via shared memory (which is safe, if you use the provided primitives), and a "snooze" ability (which suspends a thread until it has new messages to read, and may be implemented with the `syscall` instruction on certain hardware architectures).

High performance applications always end up needing something like `poll`/`epoll`/`kqueue` eventually anyways, so the most globally simple architectural decision is to do _everything_ this way, such that a naive program can still simulate a system call paradigm by sending messages and immediately snoozing[^1], but a clever program can listen for events across multiple channels and operate at the speed of shared memory.

By doing everything this way, there's no fundamental difference between talking to a service that lives within kernelspace or userspace. The only part that always depends on the kernel is snoozing, which is why the kernel needs to maintain its own accounting of the channels in use system-wide and which threads a channel should wake.
## Networking optional

Many attempts at OS futurism include network transparency at low levels: after all, the future is distributed computing, right? A program doesn't need to know if the files it's accessing are actually local, or if the graphics stack it's displaying to lives on a different continent.

Or doesn't it? Networking depends on drivers and introduces novel failure modes (the latter being a serious problem for microservices, even on conventional operating systems). Now, I've used NFS before, and it can be useful to fake locality, but you're doing a fragile and slow thing that thoughtfully-written programs would prefer to be aware of. So Mercury is not going to have any such provisions built into the system, but it's not going to be hard to write such services at higher levels within the ecosystem.
## Filesystem optional

UNIX gets a lot of benefit, at least up to a certain point, by adopting an "everything is a file" philosophy. The shallow lesson you might take is that everything _should_ be a file, but I don't think that's true. The real lesson is that there was a highly interoperable lingua franca that could act as common currency between many programs that knew very little about each other, and that model happened to be files.

So, if we understand there needs to be a thing, but files don't have to be the thing, what's the thing? Mercury attempts to answer with two technologies:

1. Buffers, which may be ephemeral or persisted.
2. Channels, which are always ephemeral but may be used to deliver buffers to a process.

Consider an embedded ROM that has multiple programs. These don't need to be wrapped in a filesystem: they can be offsets (and lengths) into the address space of read-only memory. This amounts to very small amounts of metadata, while still being sufficient to run an interactive shell.

[^1]: If that feels painful to even read, well, now you have a visceral feeling for the intrinsic inefficiency of every syscall-driven architecture ever.