DEVELOP

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