How the OpenHuman Memory Module Interacts with tinymemory-api: Architecture and Implementation Guide

The OpenHuman memory module delegates all persistent storage and vector operations to the TinyMemory runtime via the tinymemory-api contract, using a host-provider shim and runtime provider selection to bridge the core application with dynamically loaded modules.

The OpenHuman project (tinyhumansai/openhuman) separates long-term data concerns from core orchestration logic by implementing a strict contract-first architecture. Rather than embedding storage engines directly, the memory module communicates with an external TinyMemory runtime through shared types defined in tinymemory-api, ensuring compile-time safety across process boundaries while supporting graceful degradation when modules are unavailable.

The Contract-First Architecture

At the foundation of this interaction lies the tinymemory-api crate, which acts as the single source of truth for all data structures and traits shared between the host application and the TinyMemory module.

Defining the tinymemory-api Contract

The vendored crate at [vendor/tinymemory/crates/tinymemory-api/src/lib.rs](https://github.com/tinyhumansai/openhuman/blob/main/vendor/tinymemory/crates/tinymemory-api/src/lib.rs) defines the wire protocol for memory operations. This includes core types such as Chunk, Metadata, SourceKind, and the MemoryProvider trait that both sides must implement. By centralizing these definitions in a dedicated crate, the system guarantees that the host and any loaded module agree on struct layouts, enum variants, and serialization formats.

[src/openhuman/memory/api/mod.rs](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/api/mod.rs) re-exports these types under the openhuman::memory::api namespace. This indirection prevents the core codebase from depending directly on vendored paths while ensuring that all memory-related components consume identical type definitions.

Host-to-Module Communication Bridge

The transition from the OpenHuman core to the TinyMemory runtime occurs through a thin shim that implements the contract on the host side and forwards operations over the TinyBus interface.

The ModuleMemoryProvider Shim

[src/openhuman/memory/host.rs](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/host.rs) contains the ModuleMemoryProvider implementation, which satisfies the MemoryProvider trait from tinymemory-api on behalf of the core. When the core invokes storage operations—such as upsert_chunk or search—this shim serializes the requests and forwards them to the dynamically loaded TinyMemory module over the bus. The shim also provides host-side fallback implementations, including NoopEmbedding, which ensures the core remains functional even when the module is absent.

Runtime Provider Selection

[src/openhuman/memory/ops/provider.rs](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/ops/provider.rs) handles the selection of the active provider at startup. If the modules feature is enabled and the TinyMemory CDylib loads successfully, the system instantiates the module-backed provider; otherwise, it falls back to NoopMemoryProvider. This logic ensures that memory::query calls resolve to a valid implementation regardless of the runtime configuration.

Module Registration and Loading

Before any communication can occur, the TinyMemory module must be registered and loaded into the process. [src/openhuman/modules/registry.rs](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/registry.rs) manages the lifecycle of loadable modules, verifying checksums and resolving artifacts for the TinyMemory runtime. Once loaded, the module exposes a bus interface implementing the same tinymemory-api traits, allowing the ModuleMemoryProvider to call it transparently without knowing implementation details.

Working with Memory Operations

All high-level memory interactions—whether querying chat history or upserting documents—flow through the public API in [src/openhuman/memory/mod.rs](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/mod.rs), which internally delegates to the selected provider using tinymemory-api types.

The following example demonstrates performing a vector search using the public query interface:

use openhuman::memory::api::{Chunk, Metadata, SourceKind};

// Search for entities across specific source types
let results = openhuman::memory::query::search_entities(
    "project requirements",
    10, // limit
    vec![SourceKind::Chat, SourceKind::Document],
).await?;

// Inspect returned chunks using the shared contract types
for chunk in results {
    println!("Found chunk {} with {} bytes", chunk.id, chunk.content.len());
}

For scenarios requiring direct provider access, you can interact with the underlying implementation:

use openhuman::memory::ops::provider::get_provider;
use openhuman::memory::api::{Chunk, Metadata, SourceKind};

// Obtain the active provider (module-backed or fallback)
let provider = get_provider();

// Construct a new chunk using contract types
let chunk = Chunk {
    id: "chunk-001".into(),
    content: b"Meeting notes...".to_vec(),
    metadata: Metadata {
        source_kind: SourceKind::Chat,
        ..Default::default()
    },
    ..Default::default()
};

// Persist through the provider interface
provider.upsert_chunk(chunk)?;

These operations compile against the same Chunk and Metadata definitions used by the TinyMemory module, ensuring that data serialized by the host deserializes correctly on the module side.

Summary

  • The tinymemory-api crate defines the contract types (e.g., Chunk, SourceKind, MemoryProvider) shared between OpenHuman and the TinyMemory runtime.
  • src/openhuman/memory/api/mod.rs re-exports these types to create a unified import surface for the memory domain.
  • src/openhuman/memory/host.rs implements ModuleMemoryProvider, forwarding host calls to the loaded module over the TinyBus while providing no-op fallbacks.
  • src/openhuman/memory/ops/provider.rs selects the concrete provider at runtime, choosing between the module implementation and a fallback based on availability.
  • src/openhuman/modules/registry.rs handles the loading and verification of the TinyMemory CDylib, registering it for host communication.
  • All public memory APIs in src/openhuman/memory/mod.rs operate on tinymemory-api types, ensuring type safety across the host-module boundary.

Frequently Asked Questions

What is tinymemory-api in the OpenHuman architecture?

tinymemory-api is the vendored Rust crate that defines the public wire protocol and data structures (such as Chunk, Metadata, and MemoryProvider) shared between the OpenHuman core and the TinyMemory runtime. It serves as the compile-time contract that ensures both sides agree on serialization formats and trait implementations, preventing runtime errors due to mismatched data layouts.

How does the OpenHuman core communicate with the TinyMemory module?

The core communicates through the ModuleMemoryProvider shim located in src/openhuman/memory/host.rs. This structure implements the MemoryProvider trait from tinymemory-api on the host side and forwards method calls—such as get_chunks or upsert_chunk—to the dynamically loaded TinyMemory module via the TinyBus RPC interface. This abstraction allows the core to treat remote module calls as local trait method invocations.

What happens if the TinyMemory module fails to load or is unavailable?

If the module fails checksum verification, cannot be loaded, or when the modules feature is disabled, src/openhuman/memory/ops/provider.rs falls back to NoopMemoryProvider. This fallback implements the MemoryProvider trait with no-op or empty-return implementations, ensuring the core application continues to function without crashing, albeit without persistent memory capabilities.

Why does the memory module re-export types from tinymemory-api instead of using them directly?

src/openhuman/memory/api/mod.rs re-exports tinymemory-api types to create a stable, semantic namespace (openhuman::memory::api) that is decoupled from the physical vendored path. This pattern allows the core to depend on a logical interface rather than the specific crate location, simplifying future refactors and ensuring that all memory-related components consume identical type definitions from a single authority.

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 →