How the TinyBus Module Loader Works in OpenHuman for Native Modules

The TinyBus module loader uses a deterministic, security-first pipeline that verifies SHA-256 digests, caches resolution results process-wide, and loads native libraries in "cheapest-first" order to ensure single-instance, reproducible module availability.

The TinyBus module loader serves as the runtime backbone of the OpenHuman project (tinyhumansai/openhuman), responsible for safely loading native modules into the TinyBus inter-process communication system. Implemented in the src/openhuman/modules crate, this loader combines compile-time whitelisting with runtime cryptographic verification to guarantee that only approved, unmodified libraries execute within the process.

The Module Registry: A Compile-Time Whitelist

The foundation of the loading system resides in src/openhuman/modules/registry.rs, which defines a static table of every module the binary is permitted to load. This registry acts as an auditable whitelist where each entry is a ModuleRecord containing:

  • id: A short identifier used by core components and configuration overrides.
  • bus_name: The TinyBus bus name the module implements (e.g., ai.tinyhumans.tinydocs.Documents).
  • object_path: The fully-qualified DBus-style path derived from the bus name.
  • version and release_url: The exact GitHub release tag the binary trusts.
  • assets: Platform-specific archives (.tar.gz or .zip) paired with lowercase SHA-256 digests.

The registry enforces two critical compile-time invariants. First, the object_path must match the bus_name according to the transformation format!("/{}", record.bus_name.replace('.', "/")), verified by the test every_object_path_matches_its_bus_name. Second, every digest must be a complete 64-character hex string, checked by every_digest_is_a_lowercase_sha256. These constraints ensure that reviewers can compare pinned SHA-256 values against official release checksums to confirm the binary never downloads unverified code.

Resolution Caching and the Global Gate

Since TinyBus does not support unloading libraries once they are dlopen-ed, the loader memoizes resolution outcomes for the process lifetime. In src/openhuman/modules/ops.rs, the system maintains a static cache:

enum Resolution {
    Ready,
    Failed(String),   // sanitized error message, never a path or URL
}
static RESOLUTIONS: OnceLock<Mutex<HashMap<String, Resolution>>> = OnceLock::new();

When ensure_loaded receives a request, it first checks cached_resolution for prior outcomes. If no cached entry exists, the loader acquires a global async mutex through resolve_gate to serialize concurrent load attempts. This gate prevents duplicate network traffic and guarantees deterministic outcomes when multiple tasks request the same module simultaneously.

The Loading Pipeline: Cheapest-First Resolution

The core loading logic in src/openhuman/modules/ops.rs implements a tiered resolution strategy within the ensure_loaded function. The system evaluates options in order of computational cost, returning early on success:

  1. Already-running check: Queries the TinyBus host for a loaded module matching the registry entry's bus_name.
  2. Local override: Checks config.modules.overrides or the TINYMEMORY_TEST_MODULE environment variable for developer-supplied artifacts, invoking load_local if found.
  3. Installed artifact: Searches the user cache at $XDG_CACHE_HOME/openhuman/modules/<id>/<version>/ for previously downloaded and extracted libraries.
  4. Search-path scan: Examines TinyBus-registered directories (including OPENHUMAN_MODULE_PATH) for matching libraries.
  5. Verified download: If config.modules.allow_download is enabled, the loader generates platform candidates via platform::host_candidates(), attempts runtime.host().load_github_release for each, and verifies the SHA-256 digest before extraction.

If any step succeeds, the library is loaded via TinyBus's dlopen mechanism. If all steps fail, the sanitized error is cached as Resolution::Failed, and the system returns the error without retry until process restart.

Configuration and Security Controls

The loader respects security boundaries defined in src/openhuman/config/config.rs. The Config struct exposes a modules section with flags that gate behavior before any network activity occurs:

  • enabled: Master switch for the entire module system.
  • allow_download: Permits network fetches from GitHub releases.
  • install_dir: Optional override for the cache directory.
  • overrides: Vector of {id, path} pairs enabling local development builds.

These controls enable offline deployments and sandboxed environments where modules must be pre-installed or explicitly disabled.

Public API and Usage Example

The module loader exposes two primary functions in src/openhuman/modules/ops.rs:

/// Guarantees that `id` is loaded and ready for use.
pub async fn ensure_loaded(config: &Config, id: &str) -> Result<(), String>;

/// Returns a snapshot of every known module with its current state.
pub fn list(config: &Config) -> Vec<ModuleStatus>;

Higher-level components invoke ensure_loaded before making any TinyBus calls. The following example demonstrates loading the tinyvoice module and querying system status:

use openhuman::config::Config;
use openhuman::modules::ops::{ensure_loaded, list};

#[tokio::main]
async fn main() {
    // Load global configuration from config.toml or defaults
    let config = Config::load_or_init().await.unwrap();

    // Ensure the voice module is available before first use
    match ensure_loaded(&config, "tinyvoice").await {
        Ok(()) => println!("tinyvoice ready!"),
        Err(err) => eprintln!("cannot use tinyvoice: {err}"),
    }

    // Print status of all registered modules
    for status in list(&config) {
        println!(
            "{} – {} – {} – {}",
            status.id,
            status.state,
            status.version,
            status.detail.unwrap_or_default()
        );
    }
}

Running this code produces output indicating module readiness:


tinyvoice – Ready – 0.1.5 – 
tinydocs – Available – 0.1.14 – 
tinywallet – Available – 0.5.0 – 

Summary

  • The TinyBus module loader maintains a compile-time whitelist in registry.rs where every module's identity, version, and cryptographic digest are pinned.
  • Process-wide caching via Resolution and RESOLUTIONS prevents redundant loads, while a global async gate serializes concurrent resolution attempts.
  • The cheapest-first pipeline checks running instances, local overrides, cached artifacts, search paths, and finally verified downloads to locate module libraries.
  • Security guarantees include SHA-256 verification of all downloaded archives, deterministic object path derivation from bus names, and sanitized error messages that never leak file paths or URLs.
  • The loader respects configuration boundaries defined in src/openhuman/config/config.rs, supporting offline deployments through explicit enabled and allow_download flags.

Frequently Asked Questions

How does the TinyBus module loader prevent loading malicious libraries?

The loader enforces a compile-time whitelist in src/openhuman/modules/registry.rs that contains cryptographic digests for every permitted module. Before loading any downloaded archive, the system verifies the SHA-256 hash against the registry entry and rejects any mismatch. Additionally, the loader never follows redirects that would change the target URL, ensuring the digest remains valid for the actual downloaded content.

What happens if a module fails to load during runtime?

When ensure_loaded encounters a failure, it stores a Resolution::Failed variant containing a sanitized error message in the static RESOLUTIONS cache. This failure is permanent for the process lifetime; subsequent calls return the cached error immediately without retrying the expensive load operation. To attempt loading again, the process must restart after fixing the underlying issue (such as network connectivity or configuration permissions).

Can developers test local module builds without modifying the registry?

Yes. The loader checks config.modules.overrides and the TINYMEMORY_TEST_MODULE environment variable before consulting the registry or download logic. Developers can point to a locally built shared library path through these mechanisms, causing load_local to execute instead of the standard resolution pipeline. This override takes precedence over cached artifacts and remote downloads but respects the same safety boundaries regarding library validation.

Why does the loader use a global async mutex for module resolution?

The resolve_gate mutex in src/openhuman/modules/ops.rs ensures that only one task attempts to download or locally load a specific module at a time. This prevents race conditions where concurrent requests might trigger multiple simultaneous downloads of the same large binary, wasting bandwidth and creating file system conflicts. Once a module resolves successfully, the result is cached, making subsequent requests instantaneous regardless of the mutex state.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →