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 .muflo is 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 .muflo file. 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 .muflo after 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.