𧬠MAP / Holons WASM Build Guidelines¶
Overview¶
This document describes the conventions and constraints for building WebAssembly (WASM) targets in the MAP Holons codebase β specifically the guest-side Holochain hApp.
In this architecture:
- The happ/ workspace builds the Holochain zomes (guest-side logic).
- The host/ workspace builds the native Tauri runtime and clients.
- The crates/ directory holds shared code that must remain WASM-safe.
- The tests/ workspace runs native integration tests using Sweettest.
The goal is a hybrid monorepo that maintains strict build isolation between WASM and native targets while keeping shared code ergonomic and consistent.
π§± WASM Workspace Purpose¶
The happ/ workspace (formerly wasm/) produces the guest-side build artifacts:
- .wasm binaries for each zome
- dna.yaml and happ.yaml definitions (in workdir/)
- Optional Holochain-specific metadata (integrity, coordinator zomes)
These builds target the Holochain conductor runtime and must conform to Holochain Guest WASM constraints (see below).
π Directory Structure¶
map-holons/
βββ Cargo.toml # Unified workspace metadata (for tooling only)
βββ crates/ # Shared dual-target crates (WASM-safe)
β βββ base_types/
β βββ core_types/
β βββ holons_core/
β βββ holons_prelude/
β βββ holon_dance_builders/
β βββ shared_validation/
β βββ ...
β
βββ happ/ # 𧬠Guest-side hApp (Holochain zomes)
β βββ Cargo.toml # WASM build target configuration
β βββ crates/
β β βββ holons_guest/ # Guest zome logic
β βββ zomes/
β β βββ coordinator/holons/
β β βββ integrity/holons_integrity/
β βββ workdir/
β βββ dna.yaml
β βββ happ.yaml
β βββ web-happ.yaml
β
βββ host/ # π₯οΈ Host-side runtime (clients + adapters)
β βββ tauri-app/ # Rust client orchestrator (Tauri command handlers)
β βββ crates/ # Client + adapter crates
β βββ ui/ # Frontend code (TypeScript)
β
βββ tests/ # π§ͺ Integration & sweetests suite
βββ sweetests/
βοΈ Building the hApp¶
From the repo root or happ/ directory:
cargo build --manifest-path happ/Cargo.toml --target wasm32-unknown-unknown --release
This produces .wasm binaries for each zome inside:
happ/target/wasm32-unknown-unknown/release/
Use hc dna pack and hc app pack to package your zomes into DNA/hApp bundles defined in workdir/.
β Shared Crate Rules for WASM Safety¶
Crates under crates/ may be used by both the host and happ workspaces, but they must satisfy WASM safety rules.
| Rule | Description | Example |
|---|---|---|
| No Tokio / async executors | WASM cannot spawn or block threads | β tokio::spawn() |
| No native I/O | No filesystem, sockets, or native concurrency | β std::fs::File, std::net |
No std::thread |
No threading in guest WASM | β thread::spawn() |
No block_on |
Holochain guest has no async runtime | β futures::executor::block_on() |
| Pure sync functions only | Guest must be deterministic and single-threaded | β
normal fn |
async fn allowed only in traits |
Enables abstraction across host + guest | β
trait async fn definitions only |
hdk must be built with default-features = false |
Avoid Tokio contamination | β
[dependencies] hdk = { version = "0.5", default-features = false } |
π« Common Pitfalls¶
| Pattern | Why It Fails |
|---|---|
tokio::spawn or spawn_local |
WASM guest has no scheduler or threads |
.await in guest code |
No async executor; the future never polls |
| Using HDK with default features | Pulls Tokio and Mio (breaks WASM build) |
| Writing to filesystem | No file access inside guest sandbox |
| Spawning background tasks | Non-deterministic; forbidden by Holochain runtime |
π§© Integration with Host Workspace¶
Although the happ and host workspaces are isolated for build safety, they interoperate at runtime.
Flow:¶
- The
hostworkspace builds and runs the Tauri application. - It launches a Holochain Conductor that loads
.dnaand.wasmartifacts fromhapp/workdir/. - Guest zomes (compiled to
.wasm) execute within the conductor sandbox. - Communication occurs via the Conductor API, using Rust client adapters and
TrustChannelorchestration.
Important:¶
- The
hostnever compiles the guest zomes. - The
happnever links to native crates or Tokio. - They interact only via the conductor and well-defined serialization boundaries.
π Build Isolation Summary¶
| Target | Workspace | Features | Build Command |
|---|---|---|---|
| Guest (WASM) | happ/ |
default-features = false |
cargo build --target wasm32-unknown-unknown |
| Host (Native) | host/ |
full features allowed | cargo build --manifest-path host/Cargo.toml |
| Tests | tests/ |
full features allowed | cargo test --manifest-path tests/Cargo.toml |
The root Cargo.toml is metadata-only and never built directly.
π§ Quick Reference β Guest vs Host Rules¶
| Capability | Guest (WASM) | Host (Native) |
|---|---|---|
| Async I/O | β No | β Yes |
| Threads | β No | β Yes |
| Filesystem Access | β No | β Yes |
| Network Access | β No | β Yes |
tokio::spawn() |
β No | β Yes |
block_on() |
β No | β Yes |
async fn (traits) |
β Allowed | β Allowed |
async fn (impls) |
β No | β Yes |
| HDK Use | β
With default-features = false |
β With full features |
π§© Developer Workflow¶
-
Build and pack the guest WASM zomes:
npm run build:happorcargo build --manifest-path happ/Cargo.toml --target wasm32-unknown-unknownhc app pack happ/workdir
-
Build and run the host:
npm run tauri:devorcargo tauri dev --manifest-path host/tauri-app/Cargo.toml
-
The host automatically loads the
happ/workdir/happ.yamlbundle and initializes the conductor. -
Integration tests (under
tests/) run against this conductor instance using Sweettest.
π§© Key Design Principle¶
The
happ/workspace is strictly deterministic, synchronous, and platform-agnostic.
Thehost/workspace provides all asynchronous orchestration, networking, and persistence.
β Summary¶
- The
happ/workspace compiles the Holochain guest WASM (zomes) - The
host/workspace provides runtime orchestration and UI integration - Shared crates must be WASM-safe
- No async runtime or Tokio in guest code
- The root workspace file is metadata-only
- Each workspace maintains its own build isolation and Cargo.lock
This structure guarantees: - Safe, reproducible builds across WASM and native targets - Deterministic guest logic - Flexible, async-capable host orchestration - Seamless integration within a single monorepo
π§ Remember:
The hApp executes inside the Holochain conductor sandbox,
not in a browser or async runtime.
Every zome function must complete synchronously and deterministically.
Appendix A β Why This Layout Works¶
Cargo resolves dependency features globally.
If a WASM-safe crate and a Tokio-enabled crate live in the same build graph, Cargo unifies their features β breaking the WASM build.
By separating happ/ (guest) and host/ (native) physically, we prevent that contamination while keeping shared crates reusable.
Appendix B β Holochain Guest Execution Rules¶
Holochain executes guest WASM synchronously:
| Pattern | Allowed? | Notes |
|---|---|---|
async fn in free functions |
β | Guest runtime has no executor |
.await usage |
β | Futures never polled |
async fn in traits |
β | For abstraction only |
HDK externs (#[hdk_extern]) |
β | Must be synchronous |
Background tasks (tokio::spawn) |
β | Not supported |
| Multi-threading | β | Deterministic, single-threaded only |
The Conductor handles async orchestration. The guest is pure logic.
Conclusion¶
This hostβhApp hybrid workspace structure is the canonical model for all Holons and MAP projects. It combines: - Clean separation between host and guest build targets - Centralized dependency management - Reliable cross-platform builds - IDE-friendly unified workspace metadata
𧬠hApp = guest logic (inside conductor)
π§βπ» Host = conductor + client orchestration layer
Together, they form a robust architecture thatβs WASM-safe, native-optimized, and test-ready.
Appendix C β Workdir and Bundle Layout¶
The workdir/ directory acts as the bridge between Rust builds and Holochain runtime artifacts, serving as the staging area for packaging, configuration, and testing.
π Default Layout (Holons β Single hApp Repo)¶
In the Holons codebase, the workdir/ resides at the repository root, not inside happ/.
This makes it globally accessible to host, guest, and test environments alike.
map-holons/
βββ Cargo.toml
βββ crates/
βββ happ/
β βββ zomes/
β βββ crates/
β βββ Cargo.toml
βββ host/
β βββ crates/
β βββ Cargo.toml
βββ tests/
β βββ sweetests/
β
βββ workdir/ # π§© Holochain hApp packaging + runtime state
β βββ dna.yaml # DNA manifest (declares zomes and wasm paths)
β βββ happ.yaml # hApp manifest (declares DNAs and roles)
β βββ bundles/ # Built .dna and .happ bundles (hc pack outputs)
β β βββ holons.dna
β β βββ holons.happ
β βββ conductor-config.yaml # (Optional) used for local conductor/sweettest
β βββ storage/ # (Optional) persisted Holochain DHT data
β βββ temp/ # (Optional) transient conductor state or logs
π§± Purpose and Responsibilities¶
| File / Folder | Purpose |
|---|---|
dna.yaml |
Defines which zomes (and which .wasm builds) are included in the DNA. |
happ.yaml |
Defines which DNAs make up the hApp and their roles. |
bundles/ |
Output directory for packaged .dna and .happ bundles. |
conductor-config.yaml (reserved) |
Reserved for future use. Will eventually define local conductor runtime configuration (environment path, networking, and installed apps) once the merged Conductora runtime is stabilized. Not currently required or used. |
storage/ |
Persistent DHT data for long-running test conductors or local development. |
temp/ |
Temporary working directory for transient conductors and ephemeral runs. |
β οΈ Note:
Theconductor-config.yamlentry is intentionally not yet part of the active Holons toolchain.
All conductor initialization is currently handled programmatically through the runtime (e.g.,TauriConductorConfig) or the test harness.
This placeholder simply reserves the filename and location so that when configuration-file-based launches are reintroduced later, no structural changes toworkdir/will be required.
π§© Build and Packaging Flow¶
-
Build the zomes (hApp WASM):
cargo build --manifest-path happ/Cargo.toml --target wasm32-unknown-unknown --release -
Package DNA:
hc dna pack workdir/ -
Package hApp:
hc app pack workdir/ -
Result:
workdir/bundles/holons.dna workdir/bundles/holons.happ
βοΈ Usage in Tests and Runtime¶
Both the host/ conductor and the tests/sweetests/ harness load hApps directly from the workdir/.
Example β in Sweetest or conductor launch code: ```rust let happ_path = PathBuf::from("workdir/bundles/holons.happ"); let conductor = Conductor::builder() .with_happ(happ_path) .spawn() .await?;