# How OpenHuman's Memory Subsystem Integrates TinyCortex and TinyMemory

> Discover how OpenHuman's memory subsystem integrates TinyCortex and TinyMemory. Learn about its three-tier architecture, API contracts, and vector storage for agent learning.

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

---

**OpenHuman routes all agent learning through a three-tier memory architecture where TinyMemory provides the contract layer (API types and traits) and TinyCortex implements the engine layer (SQLite-backed vector storage), mediated by policy enforcement code in [`src/openhuman/memory/guard.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/guard.rs).**

OpenHuman stores conversations, documents, goals, and tool memories in a modular subsystem that decouples policy from implementation. This design allows developers to swap vector store backends without modifying host logic. The architecture separates concerns into distinct layers: the host layer manages RPC endpoints and security, the contract layer defines shared types, and the engine layer handles persistence.

## Three-Layer Architecture

The subsystem organizes functionality into clear separation layers to maintain stability across the codebase.

### Host Layer: Policy and RPC Surface

The host layer lives in `src/openhuman/memory/*` and exposes JSON-RPC endpoints such as `memory_ingest` and `memory_query`. This layer applies **taint rules**, **budget constraints**, and **PII scrubbing** before any data reaches the storage engine. The driver selection logic in [`src/openhuman/memory/driver.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/driver.rs) determines which backend fulfills requests, defaulting to `"tinycortex"`.

### Contract Layer: TinyMemory API

TinyMemory (the `tinymemory_api` crate) defines the **wire-format contract** between the host and any loaded modules. It exports core types like `MemoryCategory`, `RecallOpts`, and `MemoryIngestionRequest`, which are re-exported in [`src/openhuman/memory/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/mod.rs) for host consumption. The trait `tinymemory_api::traits::Memory` serves as the seam that all providers must implement.

### Engine Layer: TinyCortex Implementation

TinyCortex (`tinycortex::memory::*`) provides the **concrete implementation** of the contract. It manages the SQLite-backed vector store, summarisation trees, chunking pipelines, and embedding generation. The host never imports engine types directly; it communicates solely through the TinyMemory trait, enabling drop-in replacements.

## Request Flow Through the Subsystem

Every memory operation traverses a six-step pipeline that enforces security before persistence:

1. **JSON-RPC request** arrives at the OpenHuman core (e.g., `memory_ingest` or `memory_query`).
2. **Dispatch** occurs in [`src/openhuman/memory/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/ops.rs), which implements the RPC handlers and delegates to the driver.
3. **Trait invocation** happens through `tinymemory_api::traits::Memory`, ensuring the host remains agnostic to the specific engine.
4. **Driver binding** in [`src/openhuman/memory/driver.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/driver.rs) routes calls to `tinycortex::memory::MemoryConfig` by default.
5. **Guard enforcement** in [`src/openhuman/memory/guard.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/guard.rs) validates taint/scope permissions, token budgets, and scrubs PII via the `safety` module.
6. **Engine execution** writes to the SQLite vector database, updates the summarisation tree, and returns results back through the guard to the RPC layer.

## Security Guard and Policy Enforcement

The `GuardedMemory` wrapper in [`src/openhuman/memory/guard.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/guard.rs) intercepts every provider call to enforce three critical policies:

- **Taint and Scope Validation**: Ensures the current turn only accesses data from permitted sources (workspace, vault, etc.) defined in `SourceScope`.
- **Budget Enforcement**: Tracks token and embedding consumption against user-defined limits.
- **PII Scrubbing**: The `sanitize_for_storage` function in the `safety` module removes secrets before data persists to disk.

## Working with Memory: Code Examples

### Ingesting Documents

To ingest content into the memory subsystem, invoke the RPC handler with a `MemoryIngestionRequest`:

```rust
use openhuman::memory::ops::*;
use openhuman::memory::api::types::{MemoryIngestionRequest, ExtractionMode};

let request = MemoryIngestionRequest {
    user_id: user.id(),
    mode: ExtractionMode::Auto,
    inputs: vec![/* document blobs */],
    ..Default::default()
};

// Routes through driver -> TinyCortex engine
let outcome = rpc_ingest(&core_context, request).await?;
println!("Ingested {} chunks", outcome.chunks_added);

```

*Source:* [`src/openhuman/memory/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/ops.rs) – `rpc_ingest`

### Querying Memory

Retrieve relevant context using `RecallOpts` through the unified query interface:

```rust
use openhuman::memory::ops::*;
use openhuman::memory::api::types::RecallOpts;

let opts = RecallOpts {
    query: "What did the user say about project X?".into(),
    limit: 5,
    ..Default::default()
};

let result = rpc_query(&core_context, opts).await?;
for (doc, score) in result.matches {
    println!("score={:.2} → {}", score, doc.title);
}

```

*Source:* [`src/openhuman/memory/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/ops.rs) – `rpc_query`

## Extending OpenHuman with Custom Memory Providers

You can replace TinyCortex by implementing the `Memory` trait from the contract layer. Register your provider in [`src/openhuman/memory/driver.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/driver.rs) to enable selection via configuration:

```rust
use tinymemory_api::traits::Memory;
use tinymemory_api::types::{MemoryIngestionRequest, RecallOpts, IngestionOutcome, QueryOutcome, MemoryError};

#[derive(Clone)]
pub struct MyCustomProvider;

impl Memory for MyCustomProvider {
    async fn ingest(&self, req: MemoryIngestionRequest) -> Result<IngestionOutcome, MemoryError> {
        // Custom storage logic
        Ok(IngestionOutcome::default())
    }

    async fn recall(&self, opts: RecallOpts) -> Result<QueryOutcome, MemoryError> {
        // Custom retrieval logic
        Ok(QueryOutcome::default())
    }
}

```

After registering in the driver map, set your provider name in the workspace configuration to activate it.

## Summary

- **OpenHuman's memory subsystem** uses a three-layer architecture separating host policy (`src/openhuman/memory/`), API contracts (`tinymemory_api`), and engine implementation (`tinycortex`).
- **TinyMemory** provides the trait and type definitions that decouple the host from specific storage engines.
- **TinyCortex** serves as the default engine, offering SQLite-backed vector storage and summarisation trees.
- **Security enforcement** occurs in [`src/openhuman/memory/guard.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/guard.rs), applying taint checks, budget limits, and PII scrubbing before persistence.
- **Extensibility** is built-in: implement `tinymemory_api::traits::Memory` and register in [`driver.rs`](https://github.com/tinyhumansai/openhuman/blob/main/driver.rs) to swap storage backends without changing RPC handlers.

## Frequently Asked Questions

### What is the difference between TinyMemory and TinyCortex?

**TinyMemory** is the contract layer (`tinymemory_api` crate) that defines shared types and the `Memory` trait. **TinyCortex** is the engine layer that implements that trait using SQLite vector stores and tree summarisation. TinyMemory enables the host to communicate with any engine; TinyCortex is the specific engine used by default.

### How does OpenHuman enforce security policies on memory operations?

All provider calls pass through [`src/openhuman/memory/guard.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/guard.rs), where the `GuardedMemory` wrapper enforces taint/scope permissions, token budgets, and embedding limits. The `safety` module scrubs PII before data reaches the storage driver, ensuring secrets never persist to disk.

### Can I replace TinyCortex with my own vector database implementation?

Yes. Implement the `tinymemory_api::traits::Memory` trait in your custom provider, then register it in [`src/openhuman/memory/driver.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/driver.rs). The host communicates exclusively through the trait interface, so no changes are required in [`ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/ops.rs) or other host modules when swapping engines.

### Where are the RPC handlers for memory operations defined?

The JSON-RPC handlers for `memory_ingest`, `memory_query`, and related endpoints live in [`src/openhuman/memory/ops.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/ops.rs). These functions parse requests, enforce guards, and delegate to the selected driver, which forwards calls to TinyCortex or your custom provider.