Moxzi.ai - Alpha 7 - 9 actor and AI agent Platforms and a motoko ic-agent

Lots of cool stuff in alpha 7!

Motoko is now supported in 9 major AI/Agent/Actor based platforms beyond the Internet Computer -

Dapr.io
Microsoft Orleans
https://Restate.dev
https://Temporal.ai
https://Ray.io
https://Proto.Actor
Apache Pekko
https://wasmCloud.com
Cloudflare Durable Objects

There are also a bunch of optimizations, fixes, and upgrades:

0.1.0-alpha.7 (2026-09-29)

  • Release packaging: the toolchain tarball is the toolchain again (~18 MB), with optional
    bundles beside it.
    moxzi-sdk-… (the in-process runtime library, header, C example and the
    adapter sources moxzi host new copies), moxzi-hosts-… (the prebuilt Restate, wasmCloud and
    Cloudflare hosts) and moxzi-rts-static-…tar.xz (libmoxzi_rts.a) all unpack into the same
    directory. One 148 MB tarball could not be published (the site canister hashes an asset in a
    single message) and the installer downloaded all of it to keep a seventh; 68 MB of it were Go
    build outputs shipped as adapter “source” by mistake, which the release now refuses.

  • Fixed: the compiler merged same-named self-tail-recursive functions (miscompile, present in
    alpha.6).
    Two zero-argument functions of one name that call themselves in tail position –
    an iterator next that calls next(), as base’s TrieMap.entries and Text.tokens do –
    were compiled to ONE function after tail-call optimization, so one object ran the other’s code
    and trapped. It surfaced as mo:http-assets trapping in every upload (via mo:http-parser).
    Held by test/regress-behaviour/same-name-self-tail-calls.mo.

  • Fixed: a library could use names it never imported (accepted programs moc rejects).
    Imported libraries were checked in the main file’s scope, so import Iter in the main file
    made Iter resolve inside a library that did not import it. Each library now sees only its
    own imports, and such programs get moc’s exact error (M0057 / M0026). Held by
    scripts/lib_scope_gate.sh.

  • Signed-in callers on every host, each platform’s own way. A caller who presents a
    credential is authenticated by the host’s front the way its platform does – Cloudflare Access
    (Cf-Access-Jwt-Assertion, verified with WebCrypto), ASP.NET Core JwtBearer on Orleans,
    pekko-http + Nimbus on Pekko, golang-jwt on Proto.Actor / the Dapr host / Temporal, PyJWT on
    Ray, jsonwebtoken on Restate and inside the wasmCloud component, and in the standalone
    moxzi-dapr (the bearer the sidecar forwards) and moxzi-restate (verified once, journaled in
    ctx.run) – and msg.caller is the
    principal derived from (issuer, subject): the same person is the same principal on every host,
    never an actor’s. Configure MOXZI_AUTH_ISSUER, MOXZI_AUTH_AUDIENCE, MOXZI_AUTH_JWKS. A
    credential that does not verify is refused (401), never run as anonymous. The Caller Identity
    row now also proves a valid token and refuses foreign-key, expired and wrong-audience ones.

  • Security: nothing outside a host can choose an actor’s msg.caller any more. Every
    front forwarded ANY admin/{op} to the service with the client’s body, so
    admin/begin {caller: X} ran a turn as X, and admin/resume answered a parked await with
    invented bytes; the control routes (/_moxzi/deliver, hold, placement, …) had no
    authentication; Restate’s handlers were all reachable on Restate’s own ingress with a
    client-set caller; a moxzi-actor-host service took caller from any client. Now: admin
    forwards only install|passivate|drain|upgrade|state|outstanding and drops caller; the
    control surface needs MOXZI_HOST_TOKEN (loopback only without one); services need
    MOXZI_SERVICE_TOKEN (loopback only without one); Restate handlers need the token as an
    invocation header; Dapr callbacks need the sidecar’s APP_API_TOKEN. A new §61 row,
    Caller Identity, proves on every host that ingress is anonymous, a routed call is the
    calling actor, and each vector is refused (docs/host-abi.md, “Who may set msg.caller”).
    Operators of a host listening beyond loopback must now set MOXZI_HOST_TOKEN (and
    MOXZI_SERVICE_TOKEN for HTTP-mode services).

  • Fixed: candid:service printed Candid keywords bare as record fields and variant tags. A
    field called principal came out as principal: opt principal;, which does not parse, so no
    agent or host could read the interface – the ICDevs ICRC-72 orchestrator’s among them. Labels
    are now quoted exactly where moc quotes them ("principal": opt principal;); the test program’s
    section is byte-identical to moc’s. Held by scripts/candid_service_gate.sh.

  • Fixed: a timer’s oneway sends waited for the next message. Oneways a timer sent (to its
    own actor or another) ran only when something else next called the actor – on moxzid, on
    every host, and in the browser engine – so a notification sent from a timer could sit
    indefinitely. They now run in the timer’s own turn (scripts/moxzid_messages_gate.sh).

  • moxzi-dapr (Motoko actors as a Dapr app) speaks host contract v4. Every call a message
    parks is routed through the sidecar – several at once, a timer’s, and one started by a
    message that already replied – and oneway sends are delivered; timers fire on the Dapr
    reminder as messages of their own. A routed call presents the calling actor as msg.caller
    when the apps share MOXZI_DAPR_CALLER_KEY (HMAC-signed; anonymous otherwise). The matrix’s
    ICRC-72 and three v4 rows now pass on it.

  • Fixed: a remind for a hibernated actor fired nothing. The v4 timer path did not wake an
    actor that had gone to sleep with its timer due.

  • Local-actor containers have timers. An actor* container’s Timer.setTimer now fires
    (LocalRuntime::fire_timer, one local transaction; a trapping run rolls back whole), so
    moxzi.game’s loading protocol works for local-actor games (scripts/local_timer_gate.sh).

  • The real ICDevs ICRC-72 stack on all nine host platforms. The mvevent orchestrator,
    broadcaster, publisher and subscriber, built by moxzi, run end to end on Proto.Actor, Dapr,
    Temporal, Restate, Orleans, Pekko, Ray, Cloudflare and wasmCloud: publication and subscription
    registered, events published, handled by the subscriber and confirmed
    (HOST_TEST=icrc72_real_stack scripts/host_matrix_gate.sh). Getting there fixed host bugs no
    matrix row reached, among them: a due timer firing inside another message’s step, a timer armed at
    install never reported, a remind that dropped a still-armed timer, timer writes racing outside
    the key’s turn, a call to an unknown principal failing the step instead of being rejected, and a
    oneway to self replacing its sender’s answer (docs/host-abi.md, version 4).

  • Host contract v4: actors on a platform now behave like messages, not one chain of awaits.
    Three shapes of ordinary Motoko failed on every multi-process host: a timer that awaits another
    actor (its call was never routed, so the await never finished), two calls outstanding at once
    (only the first was routed), and a method that replies while a call it started is still running
    (the reply was dropped). Each step now reports the one message it ran: the invocation it
    answered, every call it started, its sends and its timer (docs/host-abi.md, version 4). All
    nine platforms (Proto.Actor, Dapr, Temporal, Restate, Orleans, Pekko, Ray, Cloudflare,
    wasmCloud) route each call independently and pass the matrix’s three new rows, in-process and
    as services (Restate’s service mode was not run: it needs a Restate server). moxzid passes them
    too (scripts/moxzid_messages_gate.sh). A host that has
    not moved still works on programs that never needed v4. Temporal: drain open workflows before
    deploying, since the workflow code changed.

  • Fixed a miscompile: return await* f() (unit f) in a oneway or an async () method
    trapped with “function invocation does not match its signature”. The implicit async of a
    function with no result components was typed async Any instead of async (), giving its
    return continuation a parameter a unit async* never passes. In a oneway the trap was silent
    and rolled the message back, so the ICDevs ICRC-72 broadcaster lost state. With this fix the
    mvevent PocketIC integration suite passes on canisters built by moxzi, as it does on moc’s.
    Held by scripts/regress_behaviour_gate.sh (both compilers on PocketIC, one moc transcript).

  • Three type-checker gaps that kept the ICDevs ICRC-72 canisters from compiling are fixed
    (moc accepted all three). A oneway public func f() { await* g() } with no return type was
    M0038; an async* function passed where a <system> async* function type is expected was
    M0096; a class field reading a module-path alias (let Vector = Types.Current.Vector) was
    M0055. moxzi also emits moc’s M0242 warning on an implicit oneway now. The real orchestrator,
    broadcaster, publisher and subscriber (mvevent) build with moxzi.

  • moxzi host new <platform> <dir>: a Motoko actor inside your platform in one command.
    Writes a project – actor.mo, moxzi’s adapter for the platform in host/, a run.sh and a
    README – for Proto.Actor, Dapr, Temporal, Orleans, Akka (Pekko) or Ray (moxzi host list).
    run.sh builds the actor and the host, starts what the platform needs (Postgres in Docker, a
    Temporal dev server), hands the host the actor and calls it. Every project is run twice on the
    board: [1], then [2] from a new host process (scripts/host_new_gate.sh). Restate,
    wasmCloud and Cloudflare are not scaffolded yet: their hosts build inside the moxzi repository.

  • Three programs moc rejects are now rejected here too. An inspect whose message variant
    leaves out a shared method, queries included (M0127: moc checks the declared type by
    subtyping; moxzi checked only its shape); an async/async* carrying a type that is not
    shared, such as a local function (M0033, previously unchecked); and a generic async* T
    (a type parameter is not shared). An actor* reference is still allowed in an async*.
    Found by running the actor* port in OCaml moc against moxzi’s own fixtures.

  • Actors address each other by key; no learn step. A hosted actor asks the host’s
    management canister for another actor: moxzi_actor_of({ key = "Account/bob" }) answers the
    principal and routes it at once. The keys an actor resolves or calls travel in its image, so
    a host restart needs nothing re-learned. POST /_moxzi/learn remains for principals obtained
    another way. (Found on the way: management calls from an actor on a platform were parked as if
    remote, so raw_rand and friends could not work there; fixed.)

  • deliver answers in JSON when the turn was started with JSON, across a host restart too:
    which invocations want JSON now travels in the parked actor’s image, and all nine hosts answer
    in JSON when the runtime renders a JSON result. (Also fixed: the Cloudflare engine failed every
    JSON call – the matrix drives it in raw Candid – and dropped JSON for a parked turn.)

  • moxzi host new covers all nine platforms. Restate (Docker for the server), wasmCloud
    (nothing else) and Cloudflare (Node for wrangler dev) scaffold from PREBUILT hosts a release
    ships under hosts/ (scripts/stage_hosts.sh). Counter, ledger and saga run on each.

  • moxzi host new --example ledger|saga: two use cases, proven on six platforms. ledger
    (Account actors): a deposit retried with the same invocation id is applied once even after
    the host process is killed and restarted; an overdraft traps and rolls the whole turn back; a
    transfer awaits the other account’s credit. saga (Trip, Hotel, Flight): a booking parked on
    an await survives the host process being killed and completes when the held call is
    delivered; a full flight releases the room it took. moxzi host examples lists them;
    moxzi host principal <Type/id> prints the principal another actor calls a key by. The
    scaffold gate runs both on Proto.Actor, Dapr, Temporal, Orleans, Akka/Pekko and Ray and checks
    every answer.

  • The exactly-once record travels one entry at a time: a turn is 49 → 36 µs and stores
    ~1.4 KB (from ~1.7 KB).
    The last 32 invocation outcomes, which answer a retried turn, were
    recompressed into the image metadata on every commit. They are now 32 ring slots, a new chunk
    kind dedup beside memory and stable: a turn writes one, and a platform stores them like
    pages. All nine adapters store them; docs/host-abi.md specifies the kind for other
    platforms. An activation whose slots are missing is refused, never run without its record;
    images written before this carry the record in their metadata and still activate (their
    next commit writes the slots).

  • Restate on Linux: 50.9 ms → 5.2 ms per call. The Restate hosts now set TCP_NODELAY on
    the connection Restate opens into them; on Linux every step waited for a delayed ACK (macOS
    hid it). Linux figures now cover Proto.Actor (1.5x its own actor), Temporal (1.3x) and Restate
    (1.3x) in process (scripts/linux_host_latency.sh).

  • A turn stores ~21% fewer bytes: ~1.7 KB, from ~2.2 KB. The image metadata every commit
    rewrites now names its module (deployment: {deployment_id, module_hash}) instead of
    repeating the stable signature, interface hash and compiler version; activation reads those
    from the module. Adapters read only module_hash and are unchanged; images stored before
    this activate unchanged.

  • A committing turn is ~22% cheaper, and activation ~30% faster. Pages a turn ships are
    still raw DEFLATE, now written and read by zlib-rs instead of miniz_oxide: 63 → 49 µs a turn
    in process, 0.59 → 0.41 ms to bring an actor back from its image, for ~5% more bytes a turn
    (2.1 → 2.2 KB). Images stored before this activate unchanged.

  • The in-process runtime ships prebuilt. Release tarballs carry lib/libmoxzi_rts
    (.so/.dylib and .a), include/moxzi_rts.h, examples/rts_hello.c and the adapters
    host new copies. The release is refused unless the example compiles against the shipped
    library and runs an actor, and unless the macOS library is relocatable.

  • 100,000 actors in one process. The in-process runtime now reserves address space for
    each actor’s memory by what it holds, not ~4 GiB up front; one process ran out of address
    space at ~20,000 actors before, and now holds 100,000 (13.9 GB resident). Memory per actor,
    bytes per turn and activation time are held by a new ratchet on the release board.

  • Cold activation is ~5x faster: ~0.6 ms, from 2.9 ms. Bringing an actor back from its
    stored image hashed the 380 KB module twice, and every platform read that module from its
    store and sent it with each activation. Module hashes are now remembered, and the platform
    sends the image alone; the service asks for a module (409 {needModule: hash}) only when it
    does not already have it. All adapters speak this; the host ABI documents it.

  • A turn stores ~1.6-2.4 KB, down from ~5.8 KB (1.6 KB averaged over 200 turns, 2.4 KB over
    20,000, where the collector’s page rewrites dominate). A counter increment changes about 45 bytes, but
    each commit stored whole compressed pages plus a metadata record whose dedup list wrote every
    reply byte as a JSON number. Changed pages that the platform already holds now travel as byte
    patches inside the metadata record (applied on activation), and the dedup list is stored
    compressed. Actors with larger replies save much more: a 1 KB reply cost ~3.5 KB in every
    later commit. Images written before this still activate.

  • An in-process actor now holds ~115 KiB, down from ~10.6 MiB. The host runtime kept a full
    copy of every actor’s heap for rollback, and read every page of a new actor’s memory to build
    its first image (on macOS that read makes each page resident). Rollback now uses the
    before-images of the pages a message writes, and new actors track their writes from the
    moment they are created. Cold activation writes only the image’s non-zero pages: ~2.8 ms for
    a fresh actor. The Cloudflare Durable Object engine gets the same change, and three copies of
    the heap leave its 128 MB isolate. Every actor of a type now shares one copy of its module
    (each held two), which took the last ~460 KiB. Set MOXZI_BASELINE_VERIFY=1 to have each image checked
    against a full scan. On Cloudflare, --compact-rts keeps the wasm memory’s length near what
    the heap uses.

  • i<22 is now a syntax error, as in moc. Motoko reads </> as a comparison only with
    whitespace on both sides; otherwise it is a type-argument bracket, and moc rejects i<22,
    d>0, i <22 with M0001. moxzi accepted all of them – a program that built with moxzi
    could fail with moc. Now both agree (i <= 22 and i >= 22 are unaffected). Found by
    comparing the actor* fork against our fixtures; pinned in scripts/diagnostics_ours_gate.sh.
    If your code has an unspaced comparison, add the spaces. mo:local-actors 0.1.1 carries the
    same fix for Jobs/JobQueue.

  • Forward references now rejected where moc rejects them (M0055). A class field without a
    type annotation that reads a sibling value of the enclosing actor or module (var v = seed(i), let w = Worker()) was accepted by moxzi and rejected by moc; and an unannotated
    let in a block that reads something declared later reported M0016 instead of moc’s M0055.
    Both now match moc. Fix: annotate the field (var v : Nat = seed(i)). Also: after a type
    error moxzi no longer adds use-before-define errors (M0016) that moc never reaches. One gap
    remains, listed in scripts/diagnostics_ours_gate.sh: a field reading an annotated sibling
    is still accepted in some cases moc rejects.

  • Every host measured against its own native actor, and much faster. The host gate times
    calls end to end (MOXZI_LATENCY=N) beside a durable counter written each platform’s own
    way. Restate went from 59 ms to 6.6 ms per update, Temporal from 100 ms to 8.9 ms, Orleans
    from 4.8 ms to 2.4 ms, Proto.Actor from 3.4 ms to 2.0 ms; queries on the Postgres-backed
    hosts are now faster than the native actor’s durable write. Temporal timers no longer run
    seconds late after a crash.

  • Seven hosts for one Motoko artifact. Beyond moxzid, Dapr and Restate, customer.mo
    now runs unchanged under Orleans (moxzi/adapters/orleans, a .NET silo with one grain
    class), Cloudflare Durable Objects (moxzi/adapters/cloudflare, a Worker + DO class),
    Proto.Actor (moxzi/adapters/protoactor, Go) and Akka/Pekko Cluster Sharding
    (moxzi/adapters/pekko, Scala). Each is one class in the host’s own model speaking the
    actor-host HTTP contract in front of the moxzi-dapr service (docs/host-abi.md); each
    has a real-host gate on the board (host_adapter_http_gate.sh). docs/host-adapters.md
    records the matrices.

  • No more false “unused identifier” on an import used only in types. A library that
    imported a module for its types alone (A.E, A.T — what every generated agent façade
    does) drew M0194 from moxzi and nothing from moc; type and object paths now count as
    uses, as in moc. Pinned in scripts/diagnostics_ours_gate.sh.

  • Host ABI as WIT (moxzi/host/wit/moxzi-host.wit, wit_gate.sh), and two integration
    samples: a Temporal workflow orchestrating moxzid actors through JSON activities
    (moxzi/samples/temporal, temporal_sample_gate.sh) and Ray tasks fanning out onto a
    moxzid actor (moxzi/samples/ray, ray_sample_gate.sh).

  • mo:ic-agent: an Internet Computer agent in Motoko (mops/mo-ic-agent). Query,
    submit, poll and read canisters over the IC’s HTTP interface from Motoko – a moxzid
    actor, a game, anywhere HTTPS outcalls exist – signed as anonymous, ed25519, secp256k1,
    a host-supplied signer, or an Internet Identity delegation chain. An update call is two
    operations (submit returns the request id; poll is one read_state), so a game
    courier never blocks on the network; call composes them. Everything it receives is
    verified: certificates (BLS signature, delegation scoped to the canister or subnet, fresh
    /time) and query replies and rejections (node signatures against keys from a verified
    /subnet certificate). It speaks v3 query, v3 read_state and v4 call, routes management
    calls by effective canister id, and reads module hash, controllers, metadata, certified
    data and canister signatures.
    scripts/ic_agent_gate.sh: known-answer tests (request ids from the spec and agent-js,
    envelope bytes, keys, principals, signatures, hash trees) built by BOTH compilers, then
    moxzid against a PocketIC live gateway with agent-js as the oracle, then a mainnet query.

  • Generic self tail calls loop. func go<T>(acc : T, …) : T = … go(…) recursed
    (and exhausted the stack) where moc loops: the await-lowering pass cloned the cons in
    a function’s types but not its binder, so the tail-call pass never saw a self
    instantiation. Ported moc’s rule; the TCO gate now covers explicit and inferred
    generic cases.

  • moxzi candid-compatible old.did new.did. Can every caller of the old interface
    still call the new one? The compiler answers with actor-type subtyping (the idl:
    import makes each service a Motoko type). moxzid runs it on every upgrade: the
    ?report=1 verdict now carries subtyping_checked: true and compatible, and an
    interface-incompatible event names the method.

  • moxzi-restate: Motoko actors as Restate virtual objects (embedders). The second
    host adapter, moxzi/adapters/restate/: Restate owns the durable-execution journal,
    retries and delayed sends; moxzid owns the heap and the parked awaits. A turn is two
    journaled steps (begin, resume) around a durable object call, so a crash inside an
    await replays to the same outcome — the adapter passes all three parked-window
    conformance rows (15 PASS / 1 SKIP), and scripts/restate_adapter_gate.sh runs it under
    a real server: JSON ingress calls, a durable cross-object await, a delayed reminder.
    docs/host-adapters.md: the same customer.mo under moxzid, Dapr and Restate.

  • The compiler is 347 KB smaller (9,143,700 → 8,796,476 bytes): the actor* runtime the
    compiler carries as source text (LocalRuntimeSource.mo) is minified at embed time —
    comment lines blanked, indentation stripped, every newline kept so a trap inside the
    runtime still names its real line. 591 KB → 242 KB of text; no byte of any program
    without actor* moves.

  • M0157 (non-productive type) now fires inside actor, object and module bodies, not
    only in plain blocks and at the top level: persistent actor { type T = T; … } was
    accepted. scripts/diagnostics_ours_gate.sh holds this and other negative cases of our
    own against moc -c, listing the divergences it knows (#b [1, 2] still parses here).

  • The conformance suite’s ICRC-72 row runs on the standard’s wire types, on every host:
    a publisher, a broadcaster and a subscriber using the ICDevs packages’ exact Candid types
    (ICRC-16 data, [?PublishResult], ConfirmMessageResult), with a ONEWAY
    icrc72_handle_notification the subscriber accepts only from its broadcaster. It proves
    publish, notify and confirm; an ICRC-16 payload intact; a non-broadcaster refused; a
    redelivery absorbed; an out-of-order chain drained; a passivated subscriber woken by the
    notification. The kernel now wakes a hibernated actor on a local inter-actor call, not only
    on ingress and query.

  • Hosts route oneway calls, and present the real caller. A oneway from one actor to an
    actor placed elsewhere was silently dropped on every multi-process host, and a routed call
    arrived as the anonymous principal, so msg.caller checks between actors could not work.
    Each step now carries sends and each routed begin a caller (docs/host-abi.md); all nine
    platforms route them (Restate and Temporal durably). Found by the ICRC-72 row.

  • admin/install {arg}: create an actor with its class arguments (actor class C(args)),
    once. Every host installed actors with the empty argument, so a class that needs its
    arguments could not be placed.

  • ICRC-72 is the pub/sub answer (docs/icrc72-host-independence.md). The host-adapter
    spec’s §40 matrix against Orleans Streams, Dapr Pub/Sub, Restate, Akka and Cloudflare,
    and its §66 question answered: yes — ICRC-72 over ordinary actor calls needs only what
    the ABI already proves; host pub/sub stays outside the contract; replay is ICRC-77 over
    the publisher’s own log (§41).

  • moxzi agent-bindings <file.did>: a typed Motoko façade for a canister. Every type
    of the interface as a Motoko type, and a Facade class over an mo:ic-agent agent
    whose methods encode, call (query or update as the interface says) and decode –
    let ledger = Ledger.connectText(agent, "ryjl3-…"); await* ledger.icrc1_name(). Update
    methods also come as m_submit / m_poll. Generated for the NNS ledger’s interface and
    an every-type fixture in the gate. Agent.call uses the synchronous /api/v3 call
    endpoint first, polling only when the gateway answers 202 or lacks v3.

  • Compiler: four gaps the agent’s differential found, all fixed and pinned.
    (1) (if c { 1 } else { 2 }) *% m with m : Nat64 was M0060: isExplicitExp stopped
    at tuples and called every block “explicit”, so both operands were inferred where moc
    checks the literal side against the other (full port of is_explicit_exp; mops
    libsecp256k1 compiles again). (2) Inside a nested module, a member module calling a
    sibling declared AFTER it compiled to the wrong function-table slot (“indirect call type
    mismatch”): a forward sibling reference now re-walks once the block is bound, as a
    self-reference already did (mops ed25519). (3) case (1, #a 0) with #a : Nat64
    never matched: a tag’s literal payload was typed from the switch’s top-level scrutinee,
    not the tag pattern’s own type; it is typed by the variant field now (mops cbor tree
    decoding). (4) #a 'x' did not parse as a pattern (a char literal payload). Pinned in
    test/patterns/Patterns.mo (w1..w9, m1, m2 – moc and moxzi must agree on a replica),
    test/fixtures/literal-operand-in-block.mo, test/fixtures/codegen/17,18.

  • A library of several declarations is the implicit module moc makes of them. moc’s
    deprecated library form (M0142: declarations before an anonymous module) becomes a
    module whose PUBLIC fields are all those declarations; the anonymous module is one of
    them, not the value. import L "lib" now exposes L.A, L.B and rejects L.run
    exactly as moc does (it used to be the other way round).

  • moxzi-dapr: Motoko actors as Dapr actors (embedders). The first external host
    adapter, moxzi/adapters/dapr/: a Dapr actor host app over moxzi-host — Dapr owns
    placement, activation, routing, reminders and state; moxzi owns execution, the persistent
    heap, transactional turns, awaits and upgrades. PUT /actors/{t}/{id}/method/{m} is one
    turn (a remote await parks, is routed through the sidecar and resumed before the
    reply); a query method runs as a query; a reminder is the actor’s timer; idle
    deactivation exports the image (ActorImageRef in Dapr state). x-moxzi-invocation-id
    makes an invocation effectively-once. Conformance: 11 PASS / 5 SKIP on the fake sidecar
    (the three parked-window scenarios are declared SKIPs — Dapr is request/response), and
    scripts/dapr_adapter_gate.sh runs two apps under real sidecars: JSON invoke, a
    cross-app await routed by placement, a durable reminder.

  • A hibernated actor wakes for a query. Only ingress woke a sleeping actor; a query
    on one reported no actor at …. Found by the Dapr adapter’s lazy reactivation.

  • moxzi-runtime feature native-http: the reqwest-backed HttpOutcall.
    moxzi_runtime::outcall::ReqwestOutcall, lifted from moxzid (which now uses it), so the
    game player and moxzid share one outcall and one response shape (headers sorted).
    Off by default; the crate still builds for wasm32.

  • Games can ask for the network: capabilities: [http] in game.yaml (moxzi.game).
    A game gets nothing it did not declare; with the line the simulation’s http_request
    works (player built with --features http, as the released CLI player is); without it
    the runtime is closed and says so by name. An outcall completes inside its tick and
    saves are taken between ticks, so a restored save never re-asks. (Kernel: an attached
    HTTP provider no longer blocks heap-world capture — it is configuration, not state;
    the in-flight cases stay guarded by pending_transform/current_seq.)

  • A library can say it needs moxzi. mops.toml [moxzi] version = "<semver>" and
    features = ["local-actors", "local-actor-persistence"] are read by moxzi build from
    every dependency (the flat .mops/ tree and local path deps) and turned into the flags,
    each announced with a note:; the root’s [moc] args is applied as mops would and wins
    over a feature’s default; a typed flag always wins. A version mismatch or an unknown
    feature refuses the build naming the package and file. moxzi deps prints the resolved
    table. A project that declares nothing is byte-identical to before. mops stores the pairs
    verbatim and ignores them, so adding them is safe for moc consumers.
    Convention: docs/mops-requirements.md. Gate: scripts/mops_requirements_gate.sh.

  • mops test can run moxzi. scripts/moc-shim speaks moc’s command line for the
    subset mops uses; set [toolchain] moc = "/path/to/scripts/moc-shim" and a package’s own
    test suite runs against a moxzi-built canister on PocketIC (mops test --mode replica;
    the same pin serves mops build/check/watch). Interpreter and WASI modes are
    refused by name. Verified on ic-mops 2.13.2 and 3.3.0. Gate: scripts/mops_shim_gate.sh.

  • An await can be parked and resumed in another process (embedders; default off).
    Router::park_call lets a host take ownership of an outbound call at its await instead
    of running it nested: the caller’s message ends with its pre-await state committed and the
    router keeps the PendingCall record — the kernel’s own state is unchanged, so game
    checkpoints are untouched; Runtime::resume_held later delivers the reply or reject as a
    message of its own. Proven across a real process restart by
    runtime/tests/durable_await_spike.rs; a stale callback index after a module change traps
    (indirect call type mismatch) rather than resuming wrongly. Nothing changes for moxzid,
    moxzi-web or the CLI, whose routers never park.

  • moxzid: --upgrade-policy refuse|warn and ?report=1. An upgrade whose stable-types
    signature changed but cannot be verified (no moxzi binary found) is now REFUSED by
    default rather than warned about; --upgrade-policy warn restores the old behaviour and
    ?force=true still overrides. POST /upgrade/<actor>?report=1 returns a JSON verdict —
    the persistent-heap result and a method-level diff of the Candid interface (added,
    removed, changed; subtyping is not yet checked and the report says so). Every interface
    change is also an interface-changed event. Without ?report the reply is the same
    upgraded as before.

  • moxzi-conformance: the host-adapter conformance suite (embedders). The sixteen
    scenarios of the host-adapter spec §61 — persistence, process failure, trap rollback,
    isolation, duplicate invocation, awaits across restart, drained upgrades, operator
    cancel, timers across passivation and crash, tiny-heap-mutation bytes, upgrade
    compatibility — as one matrix any adapter runs against the same reference actor.
    moxzid’s own HostRuntime is adapter #0: 14 pass, 2 declared skips. Gate:
    scripts/conformance_gate.sh.

  • moxzi-host::HostRuntime: the host-adapter layer (embedders). Over the kernel:
    placement-driven parking of remote calls (set_placement), one-turn invoke returning
    reply / reject / suspend / trap with the effects the turn produced (parked calls, timer
    changes) after its state committed, a bounded invocation-id dedup window, a drain state
    machine for upgrades with an explicit operator cancel that rejects the continuation
    visibly, and passivate/activate moving an actor — parked awaits included — between
    runtimes through the image manifest. Two kernel primitives came with it: a placement
    predicate for park_call, and encode_snapshot/decode_snapshot, the byte form of
    the snapshot codec snapshot.bin already used.

  • moxzi-host: the host-adapter ABI as a crate (embedders). The types a platform like
    Orleans, Dapr or Restate exchanges with moxzid — actor identity with a deterministic
    principal, deployment identity, the portable actor image and its manifest, invocations,
    turn outcomes, effects, timer intents — in moxzi/host/, serde round-trip tested, described
    in docs/host-abi.md. It depends on the kernel one way; the game player never links it,
    and scripts/runtime_boundary_gate.sh on the board enforces that boundary.

  • moxzid speaks JSON. POST /call-json/<actor>/<method> and POST /query-json/<actor>/<method>
    take a JSON array of arguments and return a JSON array of results, converted against the
    actor’s own Candid interface per docs/candid-json.md (integers past 2⁵³ as decimal
    strings, blobs as base64, single-key variants, {"$some": …} only where a nested opt
    would otherwise be ambiguous; ?lossless=1 for the {"$moxzi": …} form). Errors are
    {code, message} naming the argument path. GET /openapi/<actor> generates an OpenAPI
    3.1 document from the interface, named types as components.schemas. New crate
    moxzi-json; the raw Candid endpoints are unchanged. Gate: scripts/moxzid_json_gate.sh.

  • M0131 names the flag. When the non-stable type holds an actor* instance and
    --experimental-local-actor-persistence is off, the diagnostic’s second line says so and
    names the flag and the mops feature. A type with no actor* in it keeps moc’s exact text.
    Gate: scripts/m0131_hint_gate.sh.

Help spread the word: https://x.com/afat/status/2105273713734357370