Loadable Native Modules in OpenHuman: Architecture, Security, and Implementation Guide

Loadable native modules in OpenHuman are dynamically loaded cdylib binaries that offload heavyweight capabilities—such as document codecs, language runtimes, and external connectors—while maintaining strict dependency boundaries and runtime isolation through the TinyBus contract system.

OpenHuman's core is architected as a single, lightweight Rust binary that hosts essential domains like agent orchestration, memory management, and web chat. However, resource-intensive functionality gets delegated to loadable native modules, compiled separately as cdylib artifacts. This design pattern keeps the core lean while enabling powerful, independently updatable extensions.

How Loadable Native Modules Work in OpenHuman

A loadable native module implements the TinyBus module ABI and communicates with the core through a formally defined contract in the ‑bus crate. The core manages module lifecycles through SHA‑256‑verified releases, dynamic loading via dlopen, and broker-mediated message passing.

The Module Loading Pipeline

The typical execution flow spans five stages:

  1. Configuration check – Config::modules.enabled in src/openhuman/config/schema/modules.rs determines whether module loading is permitted.

  2. Registry lookup – src/openhuman/modules/registry.rs holds an immutable table of approved releases with pinned digests.

  3. Policy publication – On startup, the core publishes a module policy via modules::memory::set_modules_policy.

  4. Lazy loading – The first RPC call requiring a module triggers dlopen. The broker instantiates a private TinyBus channel isolating the module from global event publication.

  5. Contract-based communication – All calls route through the ‑bus crate, with shared type definitions ensuring compile‑time compatibility.

Three Core Benefits of Native Modules

Dependency Boundary Enforcement

Heavy crates—PDF parsers, DOCX processors, image codecs—compile into separate modules rather than bloating the core binary. The modules::registry implementation pins exact release digests, allowing independent updates without core redeployment.

Runtime Isolation Without Processes

Each module runs in‑process but behind a TinyBus broker. The broker traps errors, panics, and timeouts, preventing a buggy native module from terminating the entire application. This achieves isolation overhead lower than process boundaries while maintaining safety.

Clean Feature-Gate Semantics

The modules Cargo feature toggles entire module families. When disabled, related RPC methods return unknown‑method rather than disabled‑error, preserving API cleanliness. The core checks config.modules.enabled before installing any policy.

Key Source Files and Responsibilities

File Role
src/openhuman/modules/registry.rs Immutable table of trusted module releases with SHA‑256 digests
src/openhuman/modules/memory.rs Reference implementation; publishes module policy via TinyBus
src/openhuman/config/schema/modules.rs Runtime configuration struct for enabling module loading
src/openhuman/modules/mod.rs Public façade re‑exports and TinyBus broker bridging
gitbooks/developing/architecture.md High‑level architecture documentation for module boundaries

Configuration and Code Examples

Enabling Modules in Configuration

[modules]
enabled = true          # Allow loading of native modules

Publishing a Module Policy Programmatically

use std::sync::Arc;
use openhuman_core::openhuman::modules::memory::set_modules_policy;

// Build policy from workspace configuration
let policy = Arc::new(my_module_policy);
set_modules_policy(policy);

Invoking Module RPC Methods

let client = core_rpc_client::new(...);
let result: DocumentResult = client
    .call("documents_generate", json!({ "format": "pdf", "input": "Hello" }))
    .await?;

When the documents module is compiled out (feature modules disabled), this call returns unknown‑method because the controller was never registered—maintaining consistent error semantics.

Contract Safety: Compile-Time API Compatibility

The module's public API lives entirely within a ‑bus crate. Any method rename, signature change, or payload type modification triggers a compile‑time error on the core side. This eliminates an entire class of runtime version mismatches that plague traditional plugin systems.

Summary

  • Loadable native modules keep OpenHuman's core binary minimal by offloading heavy, optional capabilities to separately compiled cdylib artifacts.

  • TinyBus contracts (‑bus crate) enforce compile‑time API compatibility and broker-mediated runtime isolation.

  • SHA‑256 release verification and immutable registry entries in src/openhuman/modules/registry.rs ensure only trusted code executes.

  • Feature-gate flexibility allows clean inclusion or exclusion of module families without API pollution.

  • Three architectural benefits dominate: dependency boundaries, runtime isolation, and clean feature semantics.

Frequently Asked Questions

What format must OpenHuman native modules use?

Native modules must compile as cdylib (C-compatible dynamic libraries) that implement the TinyBus module ABI. The core uses standard dlopen to load these artifacts at runtime, then bridges them into the TinyBus messaging fabric.

How does OpenHuman prevent malicious modules from executing?

The src/openhuman/modules/registry.rs file maintains an immutable, compile‑time table of approved releases. Each entry includes a SHA‑256 digest; the core verifies downloaded modules against these digests before loading. Additionally, the TinyBus broker restricts each module to a private communication channel that cannot publish global events.

Can I disable module loading entirely?

Yes. Set config.modules.enabled = false in your configuration, or compile without the modules Cargo feature. In both cases, module-dependent RPC calls return unknown‑method rather than explicit errors, keeping client code resilient to deployment differences.

What happens when a native module crashes or hangs?

The TinyBus broker intercepts panics, errors, and timeouts from loaded modules. A failing module returns structured errors to callers without propagating the failure to the core process, maintaining overall system stability even with misbehaving extensions.

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 →