Hexagonal architecture (a.k.a. ports and adapters) puts your domain logic at the centre, talking to the outside world only through well-defined interfaces ("ports"). Concrete infrastructure ("adapters") plugs into those ports from the outside. The domain never depends on a database, a framework, or an I/O library — those depend on it.
mnesis is built exactly this way, and the architecture is enforced by the crate boundary — not by convention.
pure kernel persistence edge infrastructure
┌──────────────────┐ ┌──────────────────────┐ ┌───────────────────┐
│ mnesis │ <─── │ mnesis-store │ <── │ mnesis-fjall │
│ aggregates, │ │ codecs, envelopes, │ │ mnesis-postgres │
│ events, sagas │ the │ repository, the │ the │ mnesis-inmemory │
│ │ ports │ subscription loop, │ adap-│ (concrete stores) │
│ no_std, no-alloc │ │ the store *traits* │ ters │ │
│ (pure core) │ │ no_std + alloc │ │ std │
└──────────────────┘ └──────────────────────┘ └───────────────────┘Dependencies point inwards. mnesis-fjall depends on mnesis-store depends
on mnesis; never the reverse. You can compile and test the kernel with no store
at all, and swap the store without touching a line of domain code.
In mnesis the "port" an adapter plugs into is deliberately tiny — just two traits:
RawEventStore— byte-levelappend,read_stream,read_all. The store knows nothing about your events; it moves opaque bytes and stamps versions.WakeSource— the notify half:registera subscriber andwakeit after a durable commit, so a live subscription can tail new events.
Everything richer — the typed repository, codecs, subscriptions, snapshots,
backup/restore — is built generically on top of those two traits inside
mnesis-store. An adapter implements the two ports and inherits the rest for
free. (Optional capability ports — AtomicAppend, SnapshotStore,
StreamLister — add features when an adapter can support them.)
This is not decoration. Because the seam is two small traits:
- The kernel is
no_std-capable — no adapter can dragstdor an allocator into your domain. And because the seam is so thin,mnesis-storeisno_stdtoo (+ alloc): the whole persistence edge builds for bare-metal ARM. See Embedded &no_std. - The subscription loop is written once, generically, and every adapter reuses it — there is no per-adapter copy to drift.
- A third party can write a new store against a short contract, with no access to mnesis internals, and verify it with the conformance kit.
The port/adapter boundary is why mnesis can promise a stable kernel while letting adapters evolve independently (see Stability).
- Writing a Store Adapter — implement the ports yourself.
- Adapters — the stores mnesis ships.
- Repository — the typed façade built on the ports.
- Domain-Driven Design — what lives in the centre.