Why ADAPT has the shape it does
ADAPT exists to solve one problem: let applications process sensitive data without anyone trusting anyone. Users do not have to trust operators with plaintext data, operators do not have to trust users with the business logic that governs that data, and neither side has to trust the cloud, the device, or any single piece of hardware.
That requirement drove every architectural choice that follows. To deliver on it, ADAPT had to be:
- Deterministic. The same code on the same data must always produce the same result, on any machine. Without determinism, the audit log is a guess.
- Portable. The same compiled artifact has to run on a server, in a browser, inside a secure enclave, or inside a zero-knowledge virtual machine — unchanged. A different binary per target means a different attack surface per target.
- Minimal at runtime. The thing that actually executes user data must be small enough to audit and bare enough to run wherever security demands it.
The three layers below are the answer to those requirements.
The three layers
ADAPT is structured as three independent layers:
- The MUFL language and compiler — what developers write, and what produces the portable artifact.
- The C++ evaluator core — what actually runs the artifact, anywhere.
- Runtime wrappers — convenience packaging that embeds the evaluator into a specific host environment (Node.js, the browser, an AWS Nitro Enclave, a RISC Zero zkVM, …).
The product is the first two layers. The third is plumbing.
1. MUFL → .muflo
MUFL is the language you write your application’s logic in. It is a small, special-purpose, functional language designed for one job: describe how data inside an isolated container transitions between states in response to authenticated requests, and describe nothing else. It cannot open sockets, read files, or look at the clock. Anything coming in from the outside world arrives as the input to a transaction; anything going out leaves as the transaction’s result. That is the whole surface.
The MUFL compiler (mufl-compile) takes your source and produces a
.muflo file — a portable, content-addressed compiled artifact. The
filename is the SHA-256 of the compiled code, so two evaluators on different
continents can verify they are running the same logic by comparing 32
bytes. A .muflo runs identically on every target the evaluator supports.
Write once, deploy everywhere — and prove cryptographically that it is the
same code everywhere.
A
.muflois the unit of trust. Code review, signing, and attestation all anchor to its hash.
2. The C++ evaluator core
The evaluator is a single C++ codebase that implements the entire MUFL
execution semantics. It has no network stack, no filesystem layer, no
operating system assumptions baked in. It takes a .muflo, a packet state,
and an input message, and returns a new packet state and an output message.
Nothing else.
That minimalism is the reason ADAPT can target a zero-knowledge virtual machine at all. The evaluator was demonstrated running unchanged inside RISC Zero’s zkVM — every state transition produces a succinct proof that the transition was computed correctly, verifiable by anyone without access to the data. That is the same evaluator binary you would run on a Linux server.
Today, two builds of the evaluator are shipped:
- Native (N-API) — built for Node.js on Linux/x86-64. Used by server-side ADAPT nodes and the message broker.
- WASM — built with Emscripten. Used by browser-embedded ADAPT nodes and by Node.js when a native binary is not available.
Two further builds have been demonstrated and are on the roadmap to ship as first-class targets:
- AWS Nitro Enclaves — N-API build linked against
libnsm. Hosts an ADAPT node inside an attested enclave; the evaluator participates in the enclave’s attestation chain. - RISC Zero zkVM — the evaluator compiled to RISC-V and executed inside the zkVM, producing zero-knowledge proofs of every transaction.
Other targets (mobile, additional enclave technologies) are tractable for the same reason RISC Zero was: the evaluator’s surface to its host is narrow enough to port.
3. Runtime wrappers
A .muflo and an evaluator are not a deployable application. Something has
to take messages off a network socket (or out of a browser event), hand them
to the evaluator, take the result back out, and put it on the wire. That
something is a runtime wrapper.
A wrapper is a thin TypeScript layer that:
- Hosts an instance of the evaluator (native or WASM).
- Loads one or more
.mufloartifacts (the “packets” in that ADAPT node). - Speaks the ADAPT messaging protocol to other nodes via a message broker.
- Persists packet state and the transaction log to backup storage, when the host environment supports encrypted persistence.
The wrappers ADAPT ships today — native, enclave, and browser — exist because those are the environments customers asked for first. They are not the architecture; they are convenience packaging on top of it. If you need ADAPT inside an environment we have not pre-packaged for, you write a wrapper. The evaluator surface is small enough that this is a tractable project, not a fork.
Where developers and integrators meet
Two audiences read these docs.
Developers write MUFL. They install the toolchain, build .muflo
artifacts from MUFL sources, and test them. Their day starts at
Set up your toolchain and ends at a
compiled .muflo plus the JavaScript glue that exercises it.
Integrators ship products that embed someone else’s .muflo. They do
not need the MUFL compiler. They install
@adapt-toolkit/sdk
from npm, bundle the .muflo as a static asset, and call the SDK from
their application code. Their day starts at
Embed .muflo in your app.
The two audiences share the same artifact. A developer’s .muflo is the
integrator’s input. The boundary between them is the file, not the
toolchain.
What is not the architecture
A few things that read like “ADAPT” but are not load-bearing parts of the design:
- Docker. Earlier releases distributed the toolchain as a Docker image
(
adaptframework/mufl). That was packaging convenience for a closed beta, never the architecture. The toolchain is now distributed as prebuilt compiler binaries and an npm package; Docker is no longer required for development. - The JavaScript SDK. It is the most polished wrapper today, but it is one wrapper. The evaluator does not depend on Node.js, V8, or JavaScript.
- Any specific message broker, storage backend, or network topology. The protocol is defined; the components that implement it are swappable.
If you keep the three layers — language, evaluator, wrappers — clear in your head, every other doc on this site reads more cleanly. Whatever you are trying to do, you are doing it at one of those layers.