# How TinyMemory Module Extraction Maintains a Consistent Host-Module Contract in OpenHuman

> Discover how TinyMemory module extraction ensures a consistent host-module contract in OpenHuman. Learn about type safety across process boundaries and a single source of truth.

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

---

**OpenHuman enforces type safety across process boundaries by isolating the TinyMemory wire contract in the standalone `tinymemory-api` crate, which both the core host and dynamically loaded modules consume as their single source of truth.**

The `tinyhumansai/openhuman` repository solves the **TinyMemory module extraction** boundary consistency problem by strictly separating the on-the-wire vocabulary from internal implementation details. This architectural pattern ensures that when the TinyMemory module communicates with the host, both sides reference identical type definitions for errors, chunks, and capabilities while allowing the host's internal engine to evolve independently.

## Isolating the Contract in `tinymemory-api`

The foundation of the consistency model lies in the **`tinymemory-api`** crate located at `vendor/tinymemory/crates/tinymemory-api`. This crate serves as a pure, dependency-free interface that defines every type crossing the TinyBus module boundary.

Any data structure that travels between the host and the TinyMemory module—including **errors**, **chunks**, **capabilities**, and **RPC payloads**—lives exclusively in this crate. By making `tinymemory-api` a shared dependency, both the host and the independently compiled module are guaranteed to use identical binary layouts for all cross-boundary communication.

## Host-Side Contract Consumption via Facade

The host does not directly depend on the vendor path. Instead, [`src/openhuman/memory/api.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/api.rs) provides a thin façade that re-exports the entire contract:

```rust
pub use tinymemory_api::*;

```

This pattern allows the core codebase to access the contract through `openhuman::memory::api` without importing implementation-specific modules. The façade ensures that host code remains agnostic to the physical location of the contract crate while strictly preventing leakage of internal engine types into the public API.

## Separating Internal Engine from Wire Types

The host maintains its own in-process engine, referred to as the "direct engine," within **`tinymemory-core`** and **`tinymemory-cortex`**. These crates are designated as **optional dev-dependencies** and are explicitly excluded from production binaries.

Internal configuration types such as `MemoryHostConfig` and `EmbeddingProvider` deliberately remain outside of `tinymemory-api`. This separation ensures that host-specific implementation details never accidentally cross the module boundary, preserving the contract's stability even as the internal engine undergoes refactoring.

## Compile-Time Contract Verification

To prevent silent type mismatches during development, the repository includes compile-time identity tests in [`src/openhuman/memory/api_identity_tests.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/api_identity_tests.rs). These tests assert that host-facing types are identical to their contract crate counterparts:

```rust
#[test]
fn contract_type_ids_match() {
    // If the crate versions diverge, the following type alias will fail to compile
    type _Check = tinymemory_api::MemoryError;
}

```

If the contract definitions and the host re-export diverge, the compilation fails immediately, enforcing that both sides share the **exact same type definitions**.

## Runtime Compatibility and Version Pinning

When loading the TinyMemory module, the host enforces runtime compatibility through the module loader in **[`src/openhuman/modules/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/registry.rs)**. The loader pins a specific **SHA-256-verified release** of the module and verifies the contract version before initialization.

If the module's compiled contract version differs from the host's expectation, the loader refuses to load the module. This guarantees that only compatible versions execute together, preventing runtime serialization errors that could arise from schema mismatches.

## Graceful Degradation with the Null Driver

For builds that exclude the TinyMemory module, the host falls back to a **null driver** implemented in [`src/openhuman/memory/binding.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/binding.rs). The `NullMemoryProvider` implements the same public traits as the real engine but returns `MemoryError::Unsupported` for all operations.

Because the contract crate (`tinymemory-api`) is always compiled into the host, the public API surface remains stable regardless of whether the actual module is present. Only the underlying implementation changes between the null driver and the real engine.

## Practical Code Examples

### Importing Contract Types in Host Code

Host components import the shared contract through the façade:

```rust
use openhuman::memory::api::{MemoryError, Chunk, Capabilities};

fn handle_module_error(err: MemoryError) {
    match err {
        MemoryError::InvalidPath => eprintln!("Invalid path supplied to TinyMemory"),
        MemoryError::Unsupported => eprintln!("Operation not supported by the current module"),
        _ => eprintln!("Other memory error: {:?}", err),
    }
}

```

### Implementing the Contract in a TinyMemory Module

Modules compiled against the same contract use identical types:

```rust
use tinymemory_api::{MemoryError, Chunk};

pub fn read_chunk(id: u64) -> Result<Chunk, MemoryError> {
    // Returns the contract's Chunk type guaranteed to match host expectations
    todo!()
}

```

### Conditional Provider Selection

The host switches between the real engine and the null driver based on feature flags:

```rust
use openhuman::memory::binding::{MemoryProvider, NullMemoryProvider};

fn build_provider() -> Box<dyn MemoryProvider> {
    if cfg!(feature = "tiny_memory") {
        Box::new(tinymemory_core::MemoryEngine::new())
    } else {
        Box::new(NullMemoryProvider::new())
    }
}

```

This approach maintains API consistency while allowing the host to compile without the heavy engine dependencies when the module is disabled.

## Summary

- **Contract isolation**: The `tinymemory-api` crate at `vendor/tinymemory/crates/tinymemory-api` defines the definitive wire protocol shared by both host and module.
- **Façade pattern**: [`src/openhuman/memory/api.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/api.rs) re-exports the contract to host code without exposing implementation internals.
- **Compile-time safety**: Identity tests in [`api_identity_tests.rs`](https://github.com/tinyhumansai/openhuman/blob/main/api_identity_tests.rs) enforce type equality between host and contract, failing the build on mismatch.
- **Runtime verification**: The module loader in [`registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/registry.rs) pins SHA-256-verified releases and validates contract versions before execution.
- **Implementation independence**: Host-specific types like `MemoryHostConfig` remain in optional dev-dependencies (`tinymemory-core`), ensuring only contract types cross process boundaries.

## Frequently Asked Questions

### What is the role of the `tinymemory-api` crate?

The **`tinymemory-api`** crate serves as the single source of truth for all types that cross the TinyBus module boundary. It defines the wire protocol for errors, chunks, capabilities, and RPC payloads in a dependency-free crate that both the host and the TinyMemory module link against, ensuring binary compatibility across process boundaries.

### How does OpenHuman prevent type mismatches between the host and TinyMemory module?

OpenHuman employs **compile-time identity tests** in [`src/openhuman/memory/api_identity_tests.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/api_identity_tests.rs) that assert type equality between the host's re-exported types and the original `tinymemory-api` definitions. Additionally, the **runtime loader** in [`src/openhuman/modules/registry.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/registry.rs) verifies SHA-256 digests and contract versions, refusing to load modules with incompatible schemas.

### What happens when the TinyMemory module is disabled at compile time?

When the module is disabled, the host compiles a **null driver** (`NullMemoryProvider` in [`src/openhuman/memory/binding.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/binding.rs)) that implements the same traits as the real engine but returns `MemoryError::Unsupported` for all operations. Because the contract crate is always included, the public API remains unchanged; only the backing implementation switches to the stub.

### Why are `MemoryHostConfig` and `EmbeddingProvider` excluded from `tinymemory-api`?

These types represent **host-internal implementation details** that never traverse the module boundary. By keeping them in separate crates (`tinymemory-core`, `tinymemory-cortex`) marked as optional dev-dependencies, the architecture prevents accidental leakage of host-specific configuration into the shared contract, allowing the internal engine to evolve without affecting module compatibility.