# How Loadable Native Modules Work with TinyBus ABI, Digest Gates, and Module Hosts in OpenHuman

> Discover how OpenHuman loadable native modules leverage tinybus ABI, digest gates, and module hosts for secure, verified code execution. Learn about its two-gate security.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: internals
- Published: 2026-08-29

---

**OpenHuman employs a two-gate security architecture where a compiled-in registry validates module identities and SHA-256 digests verify binary integrity before loading native `cdylib` code through the tinybus ABI.**

The tinyhumansai/openhuman repository implements a runtime plug-in system for **loadable native modules** that extends core functionality without recompiling the host binary. This architecture uses domain-specific hosts like `tinydocs` and `tinymemory` to manage capabilities such as document synthesis and memory recall, all communicating through a lightweight RPC layer called the tinybus ABI.

## The Two-Gate Security Model

OpenHuman protects against unauthorized native code execution through complementary verification layers defined in [`src/openhuman/modules/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/registry.rs) and [`src/openhuman/modules/types.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/types.rs).

### The Compiled-In Registry Gate

The first gate is a hard-coded table of known modules stored as `pub const ALL: &[ModuleRecord]` at lines 49-61 of [`src/openhuman/modules/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/registry.rs). When the core attempts to load a capability, it calls `find("tinydocs")` to retrieve a `ModuleRecord`. If the module ID does not exist in this compiled-in list, the loading process aborts immediately, ensuring only explicitly approved modules can be instantiated.

### The Digest Verification Gate

The second gate verifies binary integrity through SHA-256 hashes. Each `ModuleRecord` contains an `assets: &'static [PlatformAsset]` array where every entry includes a `sha256: &'static str` field. Before calling `dlopen`, the core downloads the archive from `release_url`, computes its SHA-256 hash, and compares it against the registry value. Tests such as `tests::every_digest_is_a_lowercase_sha256` at lines 200-207 enforce correct hash formatting.

## Registry Structure and Module Metadata

Each module is defined by the `ModuleRecord` struct in [`src/openhuman/modules/types.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/types.rs):

```rust
pub struct ModuleRecord {
    pub id: &'static str,
    pub description: &'static str,
    pub bus_name: &'static str,
    pub object_path: &'static str,
    pub version: &'static str,
    pub release_url: &'static str,
    pub assets: &'static [PlatformAsset],
    pub load: LoadPolicy,
}

```

The `PlatformAsset` struct specifies platform-specific binaries:

```rust
pub struct PlatformAsset {
    pub host_key: &'static str,
    pub archive: &'static str,
    pub sha256: &'static str,
}

```

The `host_key` (e.g., `ubuntu-22.04-x86_64`, `macos-15-arm64`) is generated by `modules::platform::candidates_for(os, arch, glibc)` and must match the current host environment exactly. The `load` field uses the `LoadPolicy` enum to specify `Lazy` or `Eager` initialization behavior.

## The Module Loading Lifecycle

When the core requires a native capability, it executes a five-phase workflow orchestrated through [`src/openhuman/modules/host.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/host.rs) and the tinybus crate:

1. **Resolve the record**: Call `find("tinydocs")` to retrieve the `ModuleRecord` from the compiled registry.
2. **Select platform asset**: Use `record.asset_for(&host_key)` where `host_key` is obtained from `modules::platform::current_host_key()`.
3. **Download and verify**: Fetch the archive from `release_url` and validate against `asset.sha256`.
4. **Create proxy**: Load the shared library via `dlopen` and instantiate `tinybus::Proxy::new(&record.bus_name, &record.object_path)`.
5. **Expose API**: Use the module's contract crate (e.g., `tinydocs_bus::Documents`) to interact with the loaded binary.

```rust
use openhuman::modules::{find, LoadPolicy};
use tinybus::Proxy;

// Resolve registry entry
let record = find("tinydocs").expect("module known");

// Select asset for current host
let host_key = modules::platform::current_host_key();
let asset = record.asset_for(&host_key).expect("supported host");

// Verify digest and create proxy (tinybus handles verification internally)
let proxy = Proxy::new(&record.bus_name, &record.object_path)
    .expect("failed to create tinybus proxy");

// Use the module API
use tinydocs_bus::Documents;
let client = Documents::new(proxy);
let doc = client.generate_docx(...).await?;

```

## Attested Proxies for Sensitive Operations

Modules handling sensitive data, such as `tinywallet` with recovery phrases, use additional verification through `attested_proxy` defined at lines 247-254 of [`src/openhuman/modules/wallet.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/wallet.rs). This function performs digest verification **before** creating the tinybus proxy, ensuring cryptographic material is only transmitted to binaries matching the pinned SHA-256 digests in the registry.

```rust
use openhuman::modules::wallet::attested_proxy;
use openhuman::config::Config;

let config = Config::load_or_init().await?;
let proxy = attested_proxy(&config).await?;

use tinywallet_bus::Wallet;
let wallet = Wallet::new(proxy);
let address = wallet.get_address(...).await?;

```

## Lazy vs. Eager Loading Policies

The `LoadPolicy` enum in [`src/openhuman/modules/types.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/types.rs) determines when native code is fetched and loaded:

**Lazy modules** (`tinydocs`, `tinywallet`, `tinyvoice`, `tinyjuice`, `tinymcp`) are downloaded and loaded only when a user invokes a feature requiring that capability. This reduces startup time and bandwidth for unused features.

**Eager modules** (`tinymemory`) are loaded at startup because the core's RPC surface and agent tool list depend on the memory engine's capabilities. The registry marks these with `load: LoadPolicy::Eager`, causing [`src/openhuman/modules/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/ops.rs) to initialize them during the core boot sequence.

## Module Hosts and Core Integration

Each native module is wrapped by a **host** implementation in `src/openhuman/modules/<module>.rs` (e.g., [`memory.rs`](https://github.com/tinyhumansai/openhuman/blob/main/memory.rs), [`documents.rs`](https://github.com/tinyhumansai/openhuman/blob/main/documents.rs)). These hosts abstract the tinybus proxy and are responsible for:

- Selecting the correct `PlatformAsset` via the registry
- Verifying the SHA-256 digest before library loading
- Creating the `tinybus::Proxy` and exposing the contract-crate API

The generic host logic resides in [`src/openhuman/modules/host.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/host.rs), while [`src/openhuman/modules/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/ops.rs) provides the glue code that integrates these hosts into the core's initialization flow, handling both lazy and eager loading policies according to the registry configuration.

## Summary

- **Two-gate security**: A compiled-in registry at [`src/openhuman/modules/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/registry.rs) validates module identity, while SHA-256 digests in `PlatformAsset` ensure binary integrity before execution.
- **TinyBus ABI**: Provides the RPC surface between the core and loaded `cdylib` binaries through `tinybus::Proxy`.
- **Load policies**: `Lazy` modules (like `tinydocs`) load on-demand, while `Eager` modules (like `tinymemory`) initialize at startup to populate core capabilities.
- **Attested proxies**: Sensitive modules use `attested_proxy` to verify digests before exposing cryptographic interfaces such as wallet recovery phrases.

## Frequently Asked Questions

### What is the tinybus ABI in OpenHuman?

The tinybus ABI is a lightweight RPC interface that enables communication between the OpenHuman core and loadable native modules. It exposes a `Proxy` struct that marshals calls across the boundary to the compiled `cdylib`, allowing the core to invoke module-specific APIs defined in contract crates like `tinydocs_bus` or `tinymemory_api` without linking the native code at compile time.

### How does OpenHuman verify native module integrity?

Integrity verification occurs through two mechanisms: first, the core checks the compiled-in registry in [`src/openhuman/modules/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/registry.rs) to confirm the module ID is explicitly approved; second, it downloads the platform-specific archive and computes its SHA-256 hash, comparing it against the `sha256` field in the `PlatformAsset` struct. If either check fails, the loading process aborts before `dlopen` is called.

### What is the difference between lazy and eager module loading?

**Lazy loading**, specified by `LoadPolicy::Lazy`, defers downloading and initializing the native binary until the user actually requests a feature that requires that module (e.g., `tinydocs` for document generation). **Eager loading**, specified by `LoadPolicy::Eager`, downloads and loads the module during core startup (e.g., `tinymemory`), ensuring the capability is available immediately for system-critical functions like agent memory management.

### How does the wallet module protect recovery phrases?

The wallet module uses `attested_proxy`, implemented in [`src/openhuman/modules/wallet.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/wallet.rs) at lines 247-254, which performs the SHA-256 digest verification **before** creating the tinybus proxy. This ensures that the encrypted recovery phrase is only transmitted to a `tinywallet` binary that matches the exact hash pinned in the registry, preventing exposure to compromised or malicious library versions.