# What is the MemoryProvider Trait in TinyMemory? The Core Interface for OpenHuman Memory Drivers

> Discover the MemoryProvider trait in TinyMemory, the essential interface for OpenHuman memory drivers. Learn how it enables ingestion, retrieval, and capability discovery.

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

---

**The `MemoryProvider` trait defines the asynchronous contract that every memory driver must implement to expose ingestion, retrieval, and capability discovery to the OpenHuman core, living in the `tinymemory_api` contract crate to ensure type stability across module boundaries.**

The `MemoryProvider` trait serves as the fundamental abstraction layer within TinyMemory, the memory subsystem of the OpenHuman framework. Defined in the upstream `tinymemory_api` crate, this trait establishes a minimal, type-stable API that both the core binary and dynamically loaded memory modules compile against. Any driver wishing to integrate with OpenHuman must implement this standardized interface to enable document storage, semantic search, and entity management.

## Core Architecture of the MemoryProvider Trait

The trait lives in the `tinymemory_api` contract crate, a dependency shared by both the host application and loadable modules. This deliberate separation ensures that interface definitions travel across the TinyBus module boundary without exposing internal implementation details like in-process caches or configuration structs.

The design follows a **minimal contract philosophy**: the trait only contains methods necessary for cross-boundary communication. Everything purely internal remains in the host crate, preventing API bloat while maintaining strict type safety.

## Required Methods and Super-Traits

Every memory driver must implement a set of core methods grouped into the base trait and related super-traits. These methods return `Result<T, MemoryError>` using the crate-wide error type, with most operations being asynchronous.

### Synchronous Metadata Methods

Two methods provide immediate, blocking access to driver metadata:

- **`driver_id(&self) -> &'static str`** – Returns a unique static string identifier (e.g., `"null"` for the built-in fallback).
- **`capabilities(&self) -> Capabilities`** – Returns a synchronous description of supported feature families, including chunks, retrieval, and scoring capabilities.

These synchronous methods allow the host to inspect a driver before initiating expensive async operations.

### Asynchronous Operation Methods

All data operations are async and fall into functional families defined by super-traits:

- **`ingest(&self, request: IngestRequest) -> Result<IngestResponse>`** – Pushes new documents, embeddings, or structured data into memory.
- **`recall(&self, query: RecallQuery) -> Result<RecallResponse>`** – Performs read-only retrieval based on semantic or structured queries.
- **Super-trait methods** – Additional families like `MemoryChunks`, `MemoryRetrieval`, and `MemoryScoring` provide `list_chunks`, `search_entities`, and `score_chunks` respectively.

## ModuleMemoryProvider: The Host Implementation

OpenHuman ships with **`ModuleMemoryProvider`**, the concrete implementation located in [`src/openhuman/modules/memory.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory.rs). This struct acts as the bridge between the core application and dynamically loaded TinyMemory modules.

The implementation forwards every trait method to the loaded module or falls back to the built-in `NullMemoryProvider` when no module is present. At `src/openhuman/modules/memory.rs#L406`, the trait implementation delegates calls while preserving the async boundary:

```rust
impl MemoryProvider for ModuleMemoryProvider {
    fn driver_id(&self) -> &'static str { self.driver_id }
    fn capabilities(&self) -> Capabilities { self.capabilities.clone() }
    // async methods delegate to the underlying module or null fallback
}

```

The struct stores the driver identifier reported by the trait:

```rust
pub struct ModuleMemoryProvider {
    /// The id reported by `MemoryProvider::driver_id`.
    driver_id: &'static str,
    // ...
}

```

*(see [`src/openhuman/modules/memory.rs#L207`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory.rs#L207))*

Before accepting a module, the host validates advertised capabilities through `ModuleMemoryProvider::verify`, cross-checking the synchronous `capabilities()` response against host-side expectations at `src/openhuman/modules/memory.rs#L21`.

## Code Examples: Working with MemoryProvider

### Initializing the Default Driver

Create a `ModuleMemoryProvider` using the standard configuration pattern:

```rust
use openhuman::modules::memory::ModuleMemoryProvider;
use std::sync::Arc;
use openhuman::config::Config;

// Build configuration from environment or test fixtures
let config = Arc::new(Config::default());

// Initialize the provider (does not load the module yet)
let provider = ModuleMemoryProvider::new(config);

// Inspect driver metadata
println!("Driver: {}", provider.driver_id());
println!("Capabilities: {:?}", provider.capabilities());

```

### Using the Null Provider for Testing

The `NullMemoryProvider` offers a lightweight, in-memory implementation for unit testing without external dependencies:

```rust
use tinymemory_api::null::NullMemoryProvider;
use openhuman::memory::api::provider::MemoryProvider;
use std::sync::Arc;

// Built-in null driver implements the trait out-of-the-box
let null_provider: Arc<dyn MemoryProvider> = Arc::new(NullMemoryProvider::new());

// Async document insertion
let ingest_req = /* build IngestRequest */;
let resp = null_provider.ingest(ingest_req).await?;
println!("Ingested rows: {}", resp.rows_inserted);

```

### Executing Retrieval Queries

Perform semantic search using the `recall` method:

```rust
use openhuman::memory::api::provider::{MemoryProvider, RecallQuery};

let query = RecallQuery::new("search terms")
    .with_top_k(5);
let result = provider.recall(query).await?;
for hit in result.hits {
    println!("Found: {}", hit.title);
}

```

## Type Stability and Module Boundaries

Because `MemoryProvider` resides in the contract crate rather than the host application, both the OpenHuman core and any compiled TinyMemory module link against identical trait definitions. This **type-stable architecture** prevents interface drift that would otherwise cause runtime failures.

Adding new functionality requires releasing a new version of `tinymemory_api` and updating the corresponding bus contract entry in the module. Without this coordination, calls resolve to `Unsupported` at runtime, protecting the system from undefined behavior across version mismatches.

Key implementation files include:
- [`src/openhuman/modules/memory.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory.rs) – `ModuleMemoryProvider` struct and verification logic
- [`src/openhuman/modules/memory_part_01.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory_part_01.rs) – Core trait implementation block
- [`src/openhuman/modules/memory_part_02.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory_part_02.rs) – Document and entity family implementations
- [`src/openhuman/modules/memory_part_03.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory_part_03.rs) – Chunks and retrieval family implementations
- [`src/openhuman/memory/api/provider.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/api/provider.rs) (contract crate) – Trait definition and super-trait declarations

## Summary

- The `MemoryProvider` trait in TinyMemory defines the essential async interface for memory operations including `ingest`, `recall`, and capability reporting.
- Located in the `tinymemory_api` contract crate, it ensures type stability between the OpenHuman core and dynamically loaded modules.
- `ModuleMemoryProvider` in [`src/openhuman/modules/memory.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory.rs) forwards trait implementations to loaded drivers or falls back to `NullMemoryProvider`.
- Synchronous methods (`driver_id`, `capabilities`) enable immediate introspection, while async methods handle data-intensive operations.
- The trait's minimal design keeps internal implementation details out of the cross-module contract.

## Frequently Asked Questions

### What is the difference between MemoryProvider and ModuleMemoryProvider?

`MemoryProvider` is the abstract trait defining the contract in the `tinymemory_api` crate, while `ModuleMemoryProvider` is the concrete host-side implementation in [`src/openhuman/modules/memory.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory.rs) that forwards trait methods to dynamically loaded modules. Think of the trait as the interface specification and `ModuleMemoryProvider` as the adapter that bridges the host application to external memory drivers.

### Why are driver_id and capabilities synchronous while other methods are async?

These methods provide immediate metadata necessary for driver selection and validation before committing to expensive operations. The host calls `capabilities()` synchronously during `ModuleMemoryProvider::verify` to confirm feature support without awaiting a runtime, while data operations like `ingest` and `recall` are async to accommodate network latency and disk I/O in real storage backends.

### How does OpenHuman handle unsupported memory operations?

The trait design uses capability advertisement and runtime error handling. If a module lacks support for a specific operation (or if the bus contract version mismatches), the call resolves to an `Unsupported` variant of `MemoryError`. The host validates capabilities upfront through `ModuleMemoryProvider::verify`, preventing attempts to invoke unimplemented functionality.

### Where is the MemoryProvider trait defined versus where it is implemented?

The trait definition lives in the contract crate `tinymemory_api` at [`src/openhuman/memory/api/provider.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/api/provider.rs), shared between core and modules. Implementations reside in multiple locations: [`src/openhuman/modules/memory.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory.rs) contains the forwarding `ModuleMemoryProvider`, while [`src/openhuman/modules/memory_part_01.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/modules/memory_part_01.rs) through [`memory_part_03.rs`](https://github.com/tinyhumansai/openhuman/blob/main/memory_part_03.rs) contain the specific family implementations. The built-in `NullMemoryProvider` offers a reference implementation for testing environments.