Building a MEX
From source to a signed, deployable archive — the path your code takes to become a topology that runs.
A MEX archive is what you ship. This page walks the path from “I have some Go source for a guest” to “the cluster is running it.”
The shape of a source tree
A typical MEX source layout:
my-app/
├── manifest.yaml ← top-level: name, version, signing
├── topology.yaml ← the Space–Path Graph
├── spaces/
│ ├── dashboard/ ← UI space
│ │ ├── space.yaml ← UI assets manifest
│ │ ├── index.html
│ │ └── assets/
│ ├── store/ ← DATA space
│ │ ├── space.yaml ← capabilities + WASM target
│ │ └── src/ ← Go source compiled to core.wasm
│ │ ├── main.go
│ │ └── go.mod
│ └── camera/ ← IO space
│ ├── space.yaml
│ └── src/
└── world/ ← optional spatial layout
└── layout.yaml
Each WASM space has a space.yaml declaring its type, entry point, and capabilities; a src/ tree for the Go source; and the build emits core.wasm into the package output.
Build steps
1 · Build each WASM space
For each non-UI space:
cd spaces/store/src
tinygo build -target wasi -scheduler=none -opt=z -o ../core.wasm .
Repeat for every WASM space. The output core.wasm lives next to each space’s space.yaml.
2 · Validate the topology
mex validate ./
mex validate runs the structural and semantic checks: the directory shape is correct, every space referenced in the topology exists, every capability is recognised, every path connects spaces that exist, every type tag is valid.
3 · Build the archive
mex build ./ -o build/my-app.mex
This:
- Copies the manifest, topology, and per-space directories into a ZIP.
- Computes SHA-256 hashes of every file.
- Writes the integrity table into the manifest.
- Optionally signs the manifest (Ed25519, with your publisher key).
You end up with a single my-app.mex file ready to ship.
4 · Submit to a cluster
From a node with zshell configured:
zshell[0] >> topo submit ./build/my-app.mex
Or via the topology YAML route:
zshell[0] >> topo submit ./topology.yaml
(The latter is convenient when iterating; for production deploys, ship the signed .mex.)
What zrms does on submit
.mex arrives at zrms
│
▼
Validate integrity hashes
│
▼ (fail → reject)
Verify signature against publisher set
│
▼ (fail → reject)
Extract archive, validate structure
│
▼
Place each space on a zhost
│
▼
For each space: hand its directory to the right runtime
│
├── WASM space → zrun: load, on_init()
├── UI space → zedge: serve assets
└── Recognizers → zevents: register
│
▼
Topology is "running"
Capabilities — declare what you’ll use
Every WASM space lists its capabilities in its space.yaml:
type: DATA
wasm: core.wasm
capabilities:
- sys.log
- data.read
- data.write
- net.emit_to
zrun enforces this at the ABI boundary. A space that calls data.write without declaring data.write aborts with a capability violation. There is no way to escalate from inside the sandbox.
The full list of capabilities lives in the ABI reference.
Deploying iteratively
In dev, you’ll often iterate on a single WASM and re-deploy:
zshell[0] >> topo stop <id> # stop the previous version
# rebuild WASM, rebuild .mex
zshell[1] >> topo submit ./build/my-app.mex
In prod, you’ll ship a new MEX with a bumped version field; zrms will roll the cluster from the old version to the new according to the deployment policy in the manifest.
A note on Anglish
Everything above describes building a MEX by hand — you write Go for each guest, you write the topology YAML, you run mex build.
You can also write a single Anglish declaration and let the Anglish compiler emit the equivalent topology and stub WASM directly. The Anglish compiler is in fact one of the producers in the MEX ecosystem — it produces the same byte-for-byte format any other tool does. Use whichever authoring path fits your problem.
See also
- MEX format reference — the normative specification.
- Guest ABI — what your WASM is calling into.
- Topology lifecycle — what happens once it’s deployed.