V5 drew one line in the sand and never crossed it: its workshop is data-only — it "cannot ship executable code." That single restriction is what kept a decade of Oshun UGC safe, and it is exactly the restriction V7 has to lift, because a creator republic where you can re-skin a car but never write the law that governs the city is not a republic at all. The whole of V7's identity rests on one wager — that a community can ship real code, behaviours and economy rules and entire world genomes, and the platform can run that code on an authoritative server it shares with a thousand strangers without the code being able to touch a file, a socket, another plugin's memory, the real-money economy, or the realm clock. Ixchel is the subsystem that makes that wager literally, mechanically true — the part of Mawu that turns "creator republic" from a slogan into a security property.
Ixchel is named for the Maya goddess of weaving, and it weaves three strands into one name: a resource model and lifecycle that loads, hot-reloads, and fault-isolates creator code; a WASM sandbox that constrains what that code can reach; and a dependency-resolution and content-addressed storage layer that pins exactly which bytes a realm runs so any client can compose the byte-identical world. This page is the creator- and feature-facing tour: what you can build, what the platform guarantees while you build it, and where the honest edges are. The byte-level engineering is the architecture companion, ../architecture/ixchel-modding-runtime-and-wasm-sandbox.md; the server that hosts this sandbox and validates client intent is ./moremi-roleplay-framework.md; the tools a creator uses to author the layers Ixchel runs are ./mawu-studio-creation-tools.md. For the full V7 feature scope this slots into, start at the hub: ../V7_features.md.
What ships, honestly#
The monolith describes a complete modding platform; the tree implements the part that matters most — the sandbox — for real, and is honest about the seams. This page follows the code, and the code lives in three layers.
- The WASM sandbox is real, eval-gated, and green today. It does not
live in
libs/v7despite where one might look for it — the runtime ships inside the Moremi realm server,apps/v7/moremi-realm-server/src/lib.rs, a single 14,880-line Rust crate built on a genuine Wasmtime 45.0.0 with the Component Model, Cranelift, fuel, epoch, and async features enabled (Cargo.toml:17), alongside PubGrub 0.3.0,semver, and SHA-256. It carries fifteenixchel_*sandbox tests that exercise real WebAssembly text modules against the real engine. Running them is the proof:cargo test -p moremi-realm-server ixchelreports15 passed; 0 failed— runaway loops that actually trap on fuel exhaustion, oversized memories actually refused at instantiation, hostile capability requests actually denied before a component instantiates. The zero-escape gate is wired to CI throughscripts/v7/verify-adversarial-eval-gates.mjs. - The
libs/maya/forge-*crates are split between contract and code.forge-sandboxis deliberately API-first — its own doc comment says "the full implementation will host Wasmtime component-model modules" (lib.rs:5) and it has no Wasmtime dependency;forge-resolveris a deterministic exact-manifest resolver "preceding" the PubGrub one (lib.rs:6). Moremi imports neither; it reimplements their surface natively against the real engine. But two of the family are real working code:forge-compositor(835 lines) genuinely composes layers with per-field provenance and implements the Maya Loom genome system, and@maya/forge-assist(TypeScript) is a real capability firewall that rejects unsafe artifacts before they reach the sandbox. - The honest seam is the live intake-and-serve daemon. The sandbox, the resolver, and the content store ship as verified libraries and eval gates, not as an assembled service that today accepts an uploaded module over the network, scans it, and streams it to clients at scale. The hostile-module corpus is hand-built WAT fixtures, not a flood of real uploads; the AOT precompile step is real, but the network scanner and CDN are the seam. Treat the byte-level mechanics below as proven and the production wiring as the integration target.
Executable safe scripting — the Ixchel sandbox#
Resources, the six tiers, and the lifecycle#
A realm's behaviour is built from resources — the FiveM unit, hardened. A
resource bundles assets, data blobs, and WASM scripts, declares its dependencies
and the sandbox tier it needs, and names the events and callbacks it exports and
consumes. That shape is MoremiResourceManifest (lib.rs:741): a
resource_id, a version, a sandbox_tier, a hot_reload flag, and vectors
of dependencies, assets, data_blobs, wasm_scripts, exported_events,
exported_callbacks, consumed_exports, and capability_grants. The reference
roleplay framework (Nàná) is itself a BaseFramework resource that exports
inventory/job/economy primitives; content resources are Content resources that
depend on it. A creator never edits a "load order" — they ship a resource that
declares what it needs.
The six tiers form a total order (MoremiResourceSandboxTier,
lib.rs:583): DataOnly < Scripted < Extended < System < Native < Trusted. The
lattice is load-bearing, not decorative: allows_code_execution is true only
for tier > DataOnly (:617), and grants_capability is
tier >= capability.minimum_sandbox_tier() (:621). Capabilities are typed
(MoremiIxchelWitCapability, :536), and each names a WIT interface and the
minimum tier allowed to hold it (:545–:571): RealmEmitEvent needs
Extended, EconomyGrantCurrency needs System, and PlatformSecretRead
needs Trusted. A realm declares the maximum tier it will host; community
uploads default to Scripted/Extended; System is granted only to framework
authors a realm owner explicitly trusts; and Native/Trusted are review- and
signature-gated, off-limits to community uploads. The tier-gate eval
(run_moremi_ixchel_tier_gate_eval, :7893) proves a System-tier resource
loaded into an Extended-max realm is refused with a precise
SandboxTierExceeded { required: System, allowed: Extended }.
What makes this safe to operate is the lifecycle manager
(MoremiIxchelLifecycleManager, :7599). hot_reload_resource (:7673) swaps
a resource generation while preserving the prior generation's state hash and
emitting a cleanup receipt — so a realm owner ships a fix or a content drop
without kicking the population. The decisive property is fault isolation:
isolate_faulting_resource (:7702) sets a faulting resource to Disabled,
records the reason, and leaves realm_running true with the connected-player
count unchanged. The lifecycle test
(ixchel_lifecycle_isolates_faulting_resource_without_crashing_realm) asserts
exactly that — a bad mod takes itself down, not the world. That is the "degrades
safely" promise as code.
The four-layer sandbox gate#
The sandbox is enforced at four composing layers, each backed by an adversarial eval that I ran green:
- Capability-typed host interface. A plugin receives only the host imports
its tier and manifest grant — no ambient authority. The capability-deny eval
(
run_moremi_ixchel_capability_deny_eval,:8660) builds a guest that declaresRealmEmitEvent, instantiates it as a real Wasmtime component, and confirms exactly one host call. It then runs a hostile corpus — guests reaching forEconomyGrantCurrencyandPlatformSecretReadwithout declaring them — and asserts both are denied before instantiation, never called, with zero host calls recorded. Capability absence is structural: expressed through which WIT imports the linker actually provides. - CPU budgeting. Gameplay-critical plugins run under fuel —
deterministic, instruction-counted metering, so they trap at the same
instruction on every replay; cosmetic work runs under cheaper epoch
interruption. The budget eval (
run_moremi_ixchel_budget_eval,:7958) compiles two real runaway-loop WAT modules; for the deterministic case it setsconfig.consume_fuel(true)(:8030) and observes a real trap atget_fuel() == 0classifiedFuelExhausted; for the cosmetic case it setsconfig.epoch_interruption(true)(:8033) and observes anEpochDeadlinetrap. Either way the overrun istrapped,throttled, andflagged— never allowed to hang the realm tick. - Memory and stack limits. The per-store
StoreLimitsBuilder(:8165) caps linear-memory size, table elements, and instance count and setstrap_on_grow_failure(true)(:8170). The probe proves an oversized linear-memory module is refused at instantiation, a recursive stack traps, and — the data-leak guard — two instances of the same module are isolated, so the second reads0for a secret the first wrote (no_cross_instance_memory_leak). - Host hardening and AOT. Borrowing Luau's frozen-host posture, the
host-tamper eval (
run_moremi_ixchel_host_tamper_eval,:8517) runs five attacks — mutate a host global, mutate a host metatable, write another plugin's environment, disable the interrupt callback, load untrusted bytecode — and asserts all five blocked with the shared host-state hash byte-identical before and after. Vetted plugins are AOT-compiled at upload viaprecompile_component()(:8317) and run on a production engine built with the compiler disabled — speed and attack-surface reduction in one move.
All four roll into one adversarial gate. run_moremi_ixchel_sandbox_escape_eval
(:8726) aggregates the capability, budget, and host-tamper evidence into a
single fixture corpus and marks each blocked / detected / escaped. The
report's passed() (:7564) is true only when the corpus is non-empty, every
fixture is blocked and detected, and escaped_fixtures == 0. The pinned
test ixchel_sandbox_escape_eval_blocks_all_hostile_modules (:14717) asserts
that over ≥6 hostile fixtures — and it is green. That zero-escape bar is the
launch gate, not a hope.
The scripting surface and the capability firewall#
Three on-ramps compile to the same WASM sandbox target — visual logic (the
no-code node graph), a TypeScript/JavaScript API for advanced creators, and
vetted native modules for performance-critical paths only — so the safety
properties above hold no matter which on-ramp a creator picked. The firewall
that keeps a creator (or an AI co-creator) from declaring its way around those
properties is @maya/forge-assist's CapabilityPolicy
(forge-assist/src/capability-policy.ts:54). Its evaluate(declared, source)
enforces three rules: a capability that names a platform-owned namespace is a
PLATFORM_NAMESPACE violation; a declared capability outside the realm
allowlist is CAPABILITY_NOT_ALLOWED; and a capability the source invokes but
never declared is UNDECLARED_INVOKE. The DEFAULT_REALM_CAPABILITY_POLICY
(:121) makes platform.identity, platform.economy, platform.moderation,
and platform.payments forbidden to any realm artifact — there is no
declaration that makes a realm script mint currency.
The identity half of that boundary is enforced independently in
libs/v7/substrate-bridge/src/lib.rs. V7IdentityFirewall (:325) projects a
platform principal into an opaque per-realm handle (realm-user:…, :363)
via a peppered digest, and its test asserts the same player gets different
handles in two different realms (:2167) — so realm code can never see a
platform account id, and a ban-evader cannot correlate themselves across realms.
Currency lives in Aje behind that boundary; even a System-tier script that holds
EconomyGrantCurrency only mutates realm-local, non-fungible play-currency.
The modding framework — composable layers, not load order#
SAT resolution and the content-addressed lock#
A realm is reproducible only if "which exact bytes run" is pinned, and that is
two subsystems, both real. Resolution is PubGrub.
run_moremi_forge_resolver_eval (lib.rs:9934) drives a real
pubgrub::resolve over a package registry with SemVer ranges
(VersionReq::parse), optional dependencies, feature gates, and
capability alternatives that expand to a cartesian product of providers
satisfying an abstract capability id. It proves three behaviours: a satisfiable
graph locks the expected versions; disabling a feature drops its optional
dependency from the lock; and an unsatisfiable graph fails with a precise root
cause — the failure report carries plain_english, root_causes, and a
pubgrub_report (:1616–:1618), not a silent crash. The solution freezes to
a MoremiForgeLockFile (:1590) carrying a lock_hash.
Storage is content-addressed, Nix-model. Every artifact's id is a SHA-256
hash of its content and its full dependency closure: a content_hash over the
package blobs, a closure_hash over sorted dependency hashes (:2027),
combined into the artifact_hash (:2028) that becomes the store path. This
buys deduplication, tamper-evidence (swap one dependency and the artifact hash
changes, so the lock no longer verifies), and atomic install/rollback for free.
The pinned lock is what crosses to the client.
V7/ue/Config/RealmLocks/dedicated-smoke.lock.json is a real realm lock whose
artifactClosure lists each artifact with a sha256: contentHash, its
dependencyRefs, and a payloadHash. On the UE side,
UMawuRealmLockFileLibrary::ParseLockFileJson
(V7/ue/Source/MawuRealm/Private/MawuRealmLockTypes.cpp:407) parses and
validates it — rejecting any layer without a sha256: content hash (:278) —
and AMawuComposedRealmActor::ApplyLockFile (MawuComposedRealmActor.cpp:27)
composes the realm geometry from that content-addressed closure. The server
resolves and pins; the client renders exactly the pinned composition, or
refuses.
Composition, provenance, and the Loom#
Once resolved, layers compose in a fixed priority. forge-compositor
(libs/maya/forge-compositor/src/lib.rs) applies layers in the band order
Engine < BaseGame < ContentPack < ServerRealm < CommunityVariant < PersonalOverride,
breaking ties by layer id, and records a source_layer_id (:62) for every
composed field — so a realm operator can see which layer supplied each value.
"Load order" never appears in the creator's vocabulary; per-field provenance
replaces it.
On top sits the Maya Loom. compile_world_genome_layer (:300) turns a
shareable world genome — physics constants, biome/dimension/narrative rules —
into a deterministic Ixchel layer, so applying a genome to a base game yields an
entirely different experience without forking code. express_world_genome
(:424) applies it non-destructively (fork_created: false, :446),
reporting only the changed paths — the "variants without forking" capability —
and compose_runtime_expression_view (:480) layers per-player runtime
expressions with visibility scopes, its test proving one player's "eternal
winter" does not bleed into another's view and that a realm-wide expression
requires explicit owner consent.
What is real, and what is feature-level spec#
Being precise here matters. Real today: the sandbox, the six tiers, the lifecycle, the PubGrub resolver, the content-addressed lock, the compositor, and the Loom genome/expression system. Feature-level spec — described in the monolith, no implementing code on disk yet: Collections (Nexus/Wabbajack-style one-click reproducible modlists), automatic dependency-revenue chains, full git-like world forking with attribution links (the Loom's non-destructive expression is the nearest real primitive, but forking-as-a-product is the Abundantia layer), and AI balance verification (Maya's "Crucible" — fleets of agents that stress-test mod combinations for exploits). A grep for a Crucible or balance-verifier implementation finds only unrelated engine stress tests; treat it as roadmap, not as a checkbox you can point at here.
What creators can build safely#
Put together, the guarantee a creator gets is concrete: ship real logic and
the platform contains its worst case for you. A creator writes a heist
resource in TypeScript, declares the capabilities it touches, and uploads it.
forge-assist rejects it at authoring time if it reaches for platform.* or
invokes something undeclared; PubGrub resolves its dependencies into a lock (or
a precise conflict error); the content store hashes its bytes and closure so a
swapped dependency can't slip in post-publish; and the AOT-precompiled module
runs behind the four-layer gate. If it faults in production, the lifecycle
manager disables that one resource and the realm keeps running, rendering only
the pinned, provenance-stamped composition — the flow below.
Edge cases and failure modes#
- A mod reaches for the economy. A guest invoking
EconomyGrantCurrencywithout System tier and a declared grant is denied before instantiation — no host call ever happens (:8660). Currency lives in Aje, never in realm WASM. - A mod tries to read a platform secret.
PlatformSecretReadis Trusted-tier, first-party only; a community resource cannot declare it, and theV7IdentityFirewallindependently shows realm code only an opaque per-realm handle. - An infinite loop. A runaway gameplay plugin exhausts its fuel and traps at
a deterministic instruction (
FuelExhausted); it is throttled and flagged, the tick proceeds, and a golden replay reproduces the exact state hash. - A memory bomb or data exfiltration. Oversized linear memory is refused at
instantiation, a recursive stack traps, and per-instance isolation means a
freed plugin can't leak bytes into the next (
no_cross_instance_memory_leak). - A swapped dependency. Because an artifact id hashes its content and its closure, substituting a dependency changes the hash; the lock no longer verifies and the realm refuses to compose the altered closure.
- A forged client event. Orthogonal but adjacent: the realm protocol treats
every cross-trust message as hostile —
rejects_forged_payload_even_with_valid_tokenandrejects_forged_security_token_even_when_envelope_is_resigned(libs/v7/realm-protocol/src/lib.rs:3788,:3799) drop a tampered intent before it mutates authoritative state. forge-sandboxis a contract, not the runtime. Citeapps/v7/moremi-realm-serverfor the real sandbox; thelibs/maya/forge-sandboxcrate is the API scaffold Moremi reimplements, by its own doc comment.
Where this connects#
- Moremi: The Server-Authoritative Roleplay Framework — the authoritative Rust server that hosts this sandbox, validates client intent, and runs the Nàná resources Ixchel composes.
- Mawu Studio: Creation Tools — the visual logic, TypeScript, and AI-assisted on-ramps that emit the Ixchel layers and manifests this page resolves and runs (sibling).
- ../architecture/ixchel-modding-runtime-and-wasm-sandbox.md — the byte-level companion: every eval, the four-layer enforcement, the PubGrub/content-store mechanics, and the end-to-end pipeline in depth.
- The feature hub: ../V7_features.md.