This page is for integrators — developers shipping an application
that contains a pre-compiled .muflo artifact. If you are the one
writing the MUFL, start with
The MUFL language instead; you
will land here at the end.
The conceptual half of this story — why a
.muflois the unit of trust and why every runtime ends up looking the same shape — lives in Architecture. This page is the how-to.
What you need before you start
- A
.muflofile. Either produced by your team’s MUFL developers, or a third-party artifact you have audited and decided to trust. Its filename is the SHA-256 hash of the compiled code; keep that hash, you will need it. - A JavaScript / TypeScript application that wants to talk to it.
- Node.js ≥ 20.19 (for server-side embedding) or a modern browser (for client-side embedding).
Step 1 — Add @adapt-toolkit/sdk to your project
npm install @adapt-toolkit/sdk
For Node.js server-side embedding, you additionally want the native N-API backend:
npm install @adapt-toolkit/sdk-native
The browser and “WASM in Node.js” cases work with just
@adapt-toolkit/sdk — it carries the WASM evaluator inside its npm
tarball, no extra fetch required.
Step 2 — Pick the right backend
@adapt-toolkit/sdk uses conditional exports
to route imports to the right evaluator binary:
// Default: WASM evaluator in the browser, N-API evaluator in Node.js.
import { AdaptEnvironment, AdaptEvaluationUnit, AdaptPacketContext }
from '@adapt-toolkit/sdk/backend';
If you specifically want the WASM evaluator in Node.js (for deterministic-across-platforms parity with the browser, for instance):
import { AdaptEnvironment } from '@adapt-toolkit/sdk/wasm-backend';
Higher-level helpers ride on top of the backend:
import { AdaptWrapper } from '@adapt-toolkit/sdk/wrapper';
import { object_to_adapt_value } from '@adapt-toolkit/sdk/utilities';
Step 3 — Bundle the .muflo
Treat the .muflo file as a static asset:
- Webpack / Vite / esbuild: import it through your bundler’s asset loader so it lands in your build output unchanged. Verify the output filename still matches the hash — a bundler that renames it will break the trust property.
- Node.js: read it from disk at startup with
fs.readFileSync. - Browser: serve it from your static-asset host or inline it as a base64 blob if the artifact is small.
Do not modify the
.mufloafter it leaves the compiler. Its hash is the only thing you and your counterparties have to verify you are running the right code.
Browser only: host the WASM evaluator at /static/wasm/
When @adapt-toolkit/sdk/backend resolves to the WASM evaluator in a
browser, the Emscripten loader fetches the evaluator binary by an
absolute URL of the form ${location.origin}/static/wasm/mufl-bindings.wasm.
That path is currently hard-coded — your app must host the file there,
or the loader will fall through to your dev server’s SPA fallback and
fail with WebAssembly.instantiate(): expected magic word 00 61 73 6d,
found 3c 21 64 6f (the <!do of an HTML response).
The binary ships inside the @adapt-toolkit/sdk tarball; just copy it
into your app’s static-asset directory:
Vite (public/ is served at site root):
mkdir -p public/static/wasm
cp node_modules/@adapt-toolkit/sdk/dist/wasm/mufl-bindings.wasm public/static/wasm/
webpack 5 with copy-webpack-plugin:
new CopyPlugin({
patterns: [{
from: 'node_modules/@adapt-toolkit/sdk/dist/wasm/mufl-bindings.wasm',
to: 'static/wasm/[name][ext]',
}],
})
Next.js: drop the file into public/static/wasm/.
You can wire this into a postinstall script so the file stays in
sync with whatever SDK version you have pinned. Node.js consumers do
not need to do anything — the SDK locates the binary on disk via
import.meta.url.
Browser only: host the protocol .muflo at /static/mufl/
The SDK ships its own internal protocol packet — a compiled .muflo
that Protocol.Initialize() loads to bootstrap the messaging layer.
On Node.js the SDK reads it directly from its installed location
inside node_modules/@adapt-toolkit/sdk/dist/mufl_files/, so no
action is required. In the browser the SDK fetches it from
${location.origin}/static/mufl/<hash>.muflo; your app must serve
the file at that URL or Protocol.Initialize() will reject with
Error while fetching code object file: ....
Vite:
mkdir -p public/static/mufl
cp node_modules/@adapt-toolkit/sdk/dist/mufl_files/*.muflo public/static/mufl/
webpack 5:
new CopyPlugin({
patterns: [{
from: 'node_modules/@adapt-toolkit/sdk/dist/mufl_files',
to: 'static/mufl',
}],
})
Next.js: drop the file(s) into public/static/mufl/.
This requirement is for the SDK’s own protocol artefact only. Your
own application .muflo (the one carrying your packet logic) is
loaded via whatever mechanism you choose in Step 4 — typically
fetch to a URL of your choosing — and has no fixed path
convention.
Step 4 — Load the packet and run a transaction
The minimum runnable shape:
import { AdaptEnvironment, AdaptEvaluationUnit, AdaptPacketContext }
from '@adapt-toolkit/sdk/backend';
import { object_to_adapt_value } from '@adapt-toolkit/sdk/utilities';
// 1. Initialise the evaluator. Once per process.
await AdaptEnvironment.InitializeAsync(false /* test mode */);
// 2. Load the .muflo into an evaluation unit.
const muflo: Uint8Array = /* read your .muflo bytes */;
const unit = AdaptEvaluationUnit.LoadFromContents(muflo);
// 3. Instantiate a packet from the unit.
let packet = AdaptPacketContext.Create(unit, /* seed phrase */ 'my-seed');
// 4. Submit a transaction.
const envelope = object_to_adapt_value({
name: '::my_app::set_value',
targ: 42,
});
const result = packet.ExecuteTransaction(envelope);
packet = result.GetPacket(); // updated state
The transaction surface is whatever your MUFL packet exposes — there is
no other way in. If your packet does not declare a
get_some_value transaction, no caller can read some_value. See
Packet Interface (Transactions)
for what your MUFL contract can express.
Step 5 — Hook the packet up to a network
A loaded packet on its own only talks to its caller. To make it part of a distributed application, point a wrapper at it and connect that wrapper to a message broker. For server-side deployments add a backup-storage server to persist state across restarts.
Those components — broker, storage, the wrapper itself — are covered in Deploy your network.
Reference
For the full SDK surface, see the SDK API reference.