# Moxzi - Alpha 6 - actor\*, faster loops, and more

**URL:** <https://forum.dfinity.org/t/moxzi-alpha-6-actor-faster-loops-and-more/75752>\
**Category:** Showcase\
**Created:** [September 22, 2026, 6:41pm UTC](https://forum.dfinity.org/t/moxzi-alpha-6-actor-faster-loops-and-more/75752 "2026-09-22T18:41:18Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![skilesare](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/skilesare/32/5609_2.png) [@skilesare](https://forum.dfinity.org/u/skilesare)\
**Post date:** [September 22, 2026, 6:41pm UTC](https://forum.dfinity.org/t/moxzi-alpha-6-actor-faster-loops-and-more/75752/1 "2026-09-22T18:41:18Z")

</div>

## 0.1.0-alpha.6 (2026-09-22)

Three themes: **`actor*`** — many independently addressable, independently upgradable actors  
inside one canister; a **moc 1.16.1 baseline** , which is where the language and runtime this  
compiler tracks now sit; and **cheaper indexed loops and message arguments** — the index work  
is on by default, the other two are opt-in. Embedders also get deadlines, cooperative slices  
and checkpointed schedules.

* * *

### Added: `actor*` — many addressable actors inside one canister

If you are building something with many independent entities — accounts, rooms, agents,  
ledgers, inventories — Motoko has offered two shapes and neither fits. A `class` is cheap but  
invisible from outside the canister: no address, nobody can call it. A canister per entity is  
addressable and independently upgradable, but you pay a canister’s cost and operational weight  
for every one.

`actor*` sits between them. An instance lives in one canister’s heap, and has its own  
principal, its own Candid methods, and its own upgrade story.

```motoko
public persistent actor* class Counter(creator : Principal, initial : Nat) = me {
  var n = initial;
  public func internal_add(amount : Nat) : async* Nat { n += amount; n }; // internal
  public shared(msg) func add(amount : Nat) : async Nat { // external
    if (msg.caller != creator) throw Error.reject("only the creator may add");
    await* internal_add(amount)
  };
  public query func read() : async Nat { n };
};
var counters : [Counter] = []; // ordinary values, and they outlive an upgrade

```

The pieces:

- **Two kinds of method, and the distinction is the design.** `async*` is internal: callable  
from anywhere in the container with `await*`, never a message, no commit point, absent from  
the canister’s interface. `async` and `query : async` are external: real methods with a real  
`msg.caller`. In one line, `async*` is inside and `async` is outside.

- **An address.** `Actor.id(c)` is a principal you can hand out and store, and later turn back  
into a typed reference. A stale or retired one fails closed rather than quietly hitting  
whatever now occupies the slot.

- **Callable from anything that can call a canister.** A `public actor* class`’s external  
methods appear in the container’s Candid interface as `Class_method(id, args…)`, so dfx, an  
agent or another canister reaches a subactor by passing the principal it was handed. The  
compiler also emits a small client module, so a calling canister writes  
`Counter(service, id).add(5)` instead of spelling the façade by hand.

- **Upgrades.** A `persistent actor* class` keeps its instances across an upgrade with their  
state and identity, and you can hold them directly in a stable variable. The principals you  
handed out still name the same instances afterwards, so external callers need not be told  
anything and you do not rebuild the population from a side table of identifiers. Adding a  
method to the class does not disturb any of it. Changing the class’s _fields_ — including  
changing a stored variable’s TYPE — takes a migration function, as it would for an actor, and  
every live instance is migrated once:

- **Rights.** Timers and cycles work by the same spelling an actor uses — `Timer.setTimer`,  
`Timer.recurringTimer`, `Timer.cancelTimer`, `(with cycles = n)` — with `<system>` on class  
heads and methods carrying the capability. A synchronous method without `<system>` is  
refused rather than silently granted.

**What it costs.** From the recorded cost ladder, 10,000 children, native: a call into a  
subactor is **3,314 instructions and 48 bytes** , against **276 instructions and no allocation**  
for a plain class method — about 12x. A live instance adds roughly **704 bytes** of allocation  
footprint; that figure comes from tiny independent actors sharing one execution domain and is  
not a promise about the retained size of an actor holding real state. The honest advice: if all  
you want is encapsulated state that rolls back with the message, use a `class` — it is an order  
of magnitude cheaper and it is the right tool. Reach for `actor*` when you need an address you can hand out and validate  
later, entities that outlive an upgrade with their own migration, or entities callable from  
outside the canister. It does not suit a hot loop that touches every entity every tick.

**Limits** The feature is experimental and behind  
`--experimental-local-actors N`, with persistence behind  
`--experimental-local-actor-persistence`; `moc` cannot compile a program that uses it. A long  
sequential `await*` chain over thousands of children needs `--experimental-private-gc` on every  
target, the replica included, because that trampoline is also where the collector runs.  
Suspended continuations do not migrate across an upgrade, and quiescence is required.  
Public computation transfer, foreign invocation and async constructor effects remain forbidden.  
The guide and the introduction are both  
generated from accepted fixtures, so every line of code in them is code that ran.

### Added: two opt-in code generation options

Both default OFF, and a build without them is byte-identical to one from before them.

- **`--wasm-tail-call`** emits `return_call_indirect` where applying a continuation is the last  
thing a function does. A CPS-lowered `await*` chain then reuses one stack frame instead of  
one per link. On a sweep of 10,000 children whose method can suspend, the ordinary build  
exhausts the call stack on native, Pulley and the replica, and the tail-call build completes  
at 4,645 instructions per call against 5,385 for the private-GC trampoline. It does not  
replace the trampoline: that is also the collector’s empty-stack safe point.
- **`--candid-fast-path`** skips parsing an incoming Candid argument’s type table when its bytes  
are byte-for-byte the ones this compiler emits, which is every call from a caller using our  
own `.did`. Parsing costs about 267 instructions per table entry on every message. Record  
arguments decode 15% cheaper; a caller whose type section differs fails the comparison, takes  
the ordinary path, and pays one `memcmp`. A hit also skips a heap allocation, so a program  
that asserts an exact `rts_heap_size()` delta will see a different number under this flag.

### Added: for embedders — deadlines, cooperative slices, checkpointed schedules

These are in the `moxzi-runtime` crate, for programs that host Motoko actors rather than write  
them. All opt-in; nothing changes for an embedding that does not ask.

- **`watchdog`** gives a synchronous Wasm call a deadline. A scope covers nested calls and  
Stores created on the executing thread, and expiry is a local abort, never a commit point. It  
must not cross an async suspension or move between threads, and host blocking IO still needs  
its own timeout — an engine epoch interrupts Wasm, not arbitrary Rust.
- **`cooperative`** is an experimental synchronous admission pump: an engine `Pending` yields to  
a host callback while the message transaction stays on the owning stack. It is deliberately  
not an externally pollable runtime and not a serializable continuation; the callback may read  
its own host state but may not re-enter guest execution, and reentry is rejected rather than  
allowed to corrupt the transaction.
- **Bounded timer admission and additive scheduler checkpoints** let an embedding cap what a  
round may schedule and recover the schedule from a checkpoint, with timer admission preserved  
across the capsule. Checkpointed job cursors keep a long job resumable across restarts.

### Changed: checked index optimization is on by default

The default checked index fast path removes redundant fixed-width-to-Nat conversions at  
checked array/blob indices and retains raw snapshots for eligible immutable index  
bindings. Non-allocating small-word compound array updates also reuse the checked  
element address. Types and bounds checks are preserved. Use `--no-index-fast-path`  
(or API `indexFastPath = ?false`) for reference code generation; omitted API options  
now enable the optimization. `--index-fast-path` remains supported. See the  
index performance guide for measured scope and tests.

### Changed: moc 1.16.1 is the baseline

The compiler/RTS upgrade from 1.14.1 ports migration-history validation (M0268),  
`.vals()` and upgrade-hook deprecations (M0269/M0270), vetKD cost estimation, and  
mixin method documentation in Candid. The CLI now supports ordered `-A`, `-W`, and  
`-E` warning controls and stable `.most` sidecars, including enhanced migration  
whose Wasm no longer embeds the stable signature.

Correctness fixes cover wide Candid record skipping, oversized array allocation,  
small-word exponentiation overflow, exact-end region block tables, and safe Candid  
coercion recovery. Compiler and RTS now share the cached-GC flag and multi-value  
barrier ABI. Stock, compact, and configurable off-chain RTS builds retain Moxzi’s  
extensions and use pinned upstream sources with recorded build provenance.

Functional-parity follow-up fixes implicit-derivation depth (default 100, with a  
per-job `--implicit-derivation-depth` option), deferred-lambda output inference, and  
rejection of refutable import patterns, structural implicit ambiguity and candidate  
selection, transitive-import instance leakage, structural record field order, and  
distinct generated thunk identities, and committed implicit-instance selection.

The qualification guide documents reproducible tests,  
API changes, and limits. Optional M0236 rewrite suggestions remain unimplemented;  
Moxzi does not emit the unsafe autofix corrected upstream. Historical full-suite  
ratchets are still labeled 1.14.1; the new pinned campaign records current evidence.  
No public release or deployed compiler canister is changed by this work.

### Fixed

Most of this release’s fixes are internal to `actor*` and land with the feature. These are the  
ones that matter to a program that never uses it:

- **The GC did not know about upgraded static root arrays.** A canister that grew its static  
roots across an upgrade could have them collected out from under it. They are registered now  
(`s42-root-barrier` carries the before-and-after).
- **Fuel-backed performance counters drifted across budget refills.** They now report banked  
consumption plus fuel since the latest refill, so a counter read after a refill is not a  
smaller number than one taken before it.
- **A stack overflow was reported as something else.** Application stack exhaustion is now  
identified as itself, rather than surfacing as an unrelated failure — which is what made the  
`actor*` depth limits measurable in the first place.
- **A missing explicitly selected compiler was ignored.** `--compiler <path>` pointing at a file  
that is not there is an error; it used to fall back to the search path and build with a  
compiler you did not ask for.
- **An upgrade of a suspended actor container is refused** rather than producing a canister whose  
in-flight work cannot be resumed.
- **Deeply recursive helper functions could exhaust the canister stack.** A self tail call  
inside a _named nested_ function — `func go(...)` declared within another function and  
calling itself in tail position — was not being turned into a loop, so it consumed a stack  
frame per iteration and trapped with a stack overflow at roughly 24,000 levels. Anonymous  
and top-level functions were optimized correctly, which is why the effect was invisible  
until a program leaned on `mo:core`’s `pure/List` accumulator loops at depth: the Ethereum  
Foundation’s BLS12-381 `multi_inf` execution-spec fixtures trapped under moxzi while moc  
ran them in constant space. Such functions now compile to a loop, as they do under moc.  
Generic self tail calls (`func go<T>(...)` calling itself at `<T>`) are still not optimized  
and remain a known gap.
- **`and`/`or` type operands were judged for forward references in the wrong place (M0168).**  
A `type T = A and { s : S }` where `S` is declared further down the same module was rejected  
(“cannot compute intersection of types containing recursive or forward references”), even  
though the two records have disjoint fields and the intersection never needs to look inside  
`S`. moc raises only when combining actually _reaches_ an unelaborated definition; we scanned  
the operands for one anywhere. This is what kept `mo:jwt` — and therefore `evm.mo` — from  
building. Fixing it surfaced the mirror-image bug: `type A = B or C` with `B`/`C` declared  
later was accepted silently, because the union form had no M0168 check at all. Both forms now  
match moc on the reference negative suite, including the cases it _accepts_, and both report  
against the right-hand operand the way moc does.

More at [https://Moxzi.ai](https://Moxzi.ai)

---

<div class="post-metadata">

**Author:** ![skilesare](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/skilesare/32/5609_2.png) [@skilesare](https://forum.dfinity.org/u/skilesare)\
**Post date:** [September 22, 2026, 6:47pm UTC](https://forum.dfinity.org/t/moxzi-alpha-6-actor-faster-loops-and-more/75752/2 "2026-09-22T18:47:56Z")

</div>

[https://x.com/afat/status/2102469869698773467](https://x.com/afat/status/2102469869698773467)

Help spread the word!

---

<div class="post-metadata">

**Author:** ![graial](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/graial/32/39419_2.png) [@graial](https://forum.dfinity.org/u/graial)\
**Post date:** [September 23, 2026, 6:34am UTC](https://forum.dfinity.org/t/moxzi-alpha-6-actor-faster-loops-and-more/75752/3 "2026-09-23T06:34:18Z")

</div>

Greetings,

if i were interested in trying out an ‘inventory canister’ feature with this, would I be working from the rust-cdk?

I’ve been appreciating your feedback. So it’d be cool to get a feel for what you are working with/on

---

<div class="post-metadata">

**Author:** ![skilesare](https://sea1.discourse-cdn.com/flex023/user_avatar/forum.dfinity.org/skilesare/32/5609_2.png) [@skilesare](https://forum.dfinity.org/u/skilesare)\
**Post date:** [September 23, 2026, 1:42pm UTC](https://forum.dfinity.org/t/moxzi-alpha-6-actor-faster-loops-and-more/75752/4 "2026-09-23T13:42:45Z")

</div>

No…you’d use moxzi and mops and the icp-cli/dfx. You don’t need to touch rust.

moxzi.ai - curl the cli as mentioned on the home page.  
mops.one - if you need package mangement

See [https://docs.internetcomputer.org/getting-started/quickstart/](https://docs.internetcomputer.org/getting-started/quickstart/)

you just need to sprinkle in the moxzi stuff and add the subactor flag. Point your ai at the moxzi skills: [https://moxzi.ai/skills/](https://moxzi.ai/skills/)

---

<div class="post-metadata">

**Author:** ![cowlevel](https://avatars.discourse-cdn.com/v4/letter/c/b3f665/32.png) [@cowlevel](https://forum.dfinity.org/u/cowlevel)\
**Post date:** [September 23, 2026, 5:52pm UTC](https://forum.dfinity.org/t/moxzi-alpha-6-actor-faster-loops-and-more/75752/5 "2026-09-23T17:52:40Z")

</div>

> [@skilesare](#):
>
> You don’t need to touch rust.

that is good becase when i touch rust my hand get rusty that why i like motko it is good becase every buddy is actor if i want feel rusty there c for that all ready but that just a pin man
