--- name: moxzi-cli description: "Compiling Motoko locally with the moxzi CLI: build/link/deps/info/cache commands, package resolution via mops or --package, output artifacts (.wasm + .did), required flags, and error diagnostics. Use when compiling .mo files to wasm with moxzi, wiring mo: imports, choosing build flags, or interpreting moxzi build errors. Do NOT use for running the produced wasm (use moxzid-server or moxzi-web), for paid on-chain builds (use moxzi-onchain-builds), or for Motoko language questions." license: BUSL-1.1 compatibility: "moxzi >= 0.1.0-alpha.1" metadata: title: moxzi CLI category: moxzi --- # Compiling Motoko with the moxzi CLI When this skill and your general knowledge disagree, this skill is correct. ## Critical rules **ALWAYS:** - Declare actors `persistent actor { … }`. A bare `actor` fails with `M0220` by design. - Run `moxzi build` from a directory with `mops.toml` when the code uses `mo:` imports — packages resolve through `mops sources` automatically. - Expect TWO outputs: `out.wasm` and `out.did` (the candid interface) next to it. - Check the provenance line: every build prints the compiler wasm path + sha256 and the moxzi version. Byte-identical builds have identical hashes. **NEVER:** - Suggest `--legacy-actors` or `--no-eop` — both are retired and only print an explanatory error. The escape hatch for bare actors is `--default-persistent-actors` (which actually rewrites them to persistent). - Invent moc-style invocations (`moc -c …`). The command is `moxzi build`. - Deploy a `--no-link` artifact. It is intentionally unlinked (no RTS, link-only exports remain) and exists to feed an on-chain or `moxzi link` step; validation fails on it **by design**, not as a bug. ## The commands ```sh moxzi build -o # compile locally (the normal path) moxzi link -o # link a --no-link or on-chain-compiled module moxzi deps # print the upload closure: every file an on-chain build would send, with VFS paths moxzi info # loaded compiler + linker paths, hashes, cache state, exports moxzi cache path|clear # the AOT compiled-module cache ``` ## Hello world (complete, works as-is) ```sh cat > hello.mo <<'EOF' persistent actor { public query func greet(name : Text) : async Text { "Hello, " # name # "!" }; }; EOF moxzi build hello.mo -o hello.wasm ``` Expected output shape: ``` hello.mo -> hello.wasm + hello.did (220356 bytes, 1 file(s), 59 steps, 0.7s) compiled by ./compiler.wasm (sha256 86ea6a…), moxzi 0.1.0-alpha.1 ``` `hello.wasm` deploys to the IC as-is (`dfx canister install --wasm hello.wasm`), runs under `moxzid`, and runs in a browser via `moxzi-web`. ## Toolchain resolution The compiler and linker are wasm files, found in this order: 1. `--compiler ` / `--linker ` flags 2. `MOXZI_COMPILER` / `MOXZI_LINKER` environment variables 3. the search path (a release tarball ships `compiler.wasm` + `linker.wasm` beside the binary) `moxzi info` reports what was actually loaded, with hashes. ## Package resolution ```sh # preferred: a mops project — nothing to pass cd my-project # has mops.toml moxzi build src/main.mo -o main.wasm # explicit: like moc --package, repeatable moxzi build main.mo -o main.wasm --package base /path/to/base/src ``` `--root ` sets what `/src` maps to (default: nearest ancestor with `mops.toml` or `dfx.json`, else the entry file's directory). Error paths are reported under `/src`. ## Flags that matter | Flag | Use | |---|---| | `--debug` | debug build | | `--no-idl` | skip writing the `.did` | | `--no-link` | stop before linking (feeds `moxzi link` or an on-chain link) | | `--timings` | per-phase timing | | `-v` | forward the compiler's own debug output | | `--stack-budget ` | scheduler yield ceiling; 0 = canister default (200). Off-chain, raising it is the difference between minutes and hours on large projects — yields are checkpoints, output bytes do not change | | `--force-gc` | collect at every message boundary; caps off-chain heap growth at instruction cost (fine locally) | | `--default-persistent-actors` | rewrite bare `actor` to `persistent actor` (moc-compatible flag) | | `--stable-regions`, `--max-stable-pages `, `--stabilization-instruction-limit `, `--measure-rts-stack`, `--trap-on-call-error` | moc-compatible passthroughs | | `--remote --canister ` | build on a compiler canister instead — see the `moxzi-onchain-builds` skill | ## Error diagnostics Everything is source-located (`/src/file.mo:line.col-line.col`) with moc's error codes. | Symptom | Meaning | Fix | |---|---|---| | `[M0220] … should be declared 'persistent'` | bare `actor` | add `persistent`, or pass `--default-persistent-actors` | | `[M0020] unresolved import mo:foo/Lib` | package not resolvable | run in a mops project, or add `--package foo ` | | `[M0050] literal of type Text does not have expected type Nat` | ordinary type error | fix the code; codes match moc's | | `expression nested too deeply (limit 128)` / `type nested too deeply (limit 128)` | machine-generated deep nesting hit the parser depth guard | chunk generated expressions/types | | entry is `module { … }` | not an error — a library build is a valid build | expected | | validate fails on a `--no-link` artifact | it is unlinked BY DESIGN | run `moxzi link` first | ## Quick reference - Build: `moxzi build entry.mo -o out.wasm` → `out.wasm` + `out.did` - Toolchain: `--compiler`/`--linker`, else `MOXZI_COMPILER`/`MOXZI_LINKER`, else search path - Packages: mops project auto-resolves; else `--package NAME PATH` (repeatable) - `persistent actor` is mandatory; `--default-persistent-actors` is the only rewrite - Related skills: run the artifact → `moxzid-server` or `moxzi-web`; trustless build → `moxzi-onchain-builds`