Layered Architecture of the Memory Subsystem in OpenHuman: A 10-Layer Technical Deep Dive

OpenHuman’s memory subsystem implements a multi-layered, contract-driven architecture that separates concerns across ten distinct layers—from wire protocol definitions to agent-facing APIs—enabling secure, extensible, and synchronized memory operations across both core runtime and dynamic modules.

The tinyhumansai/openhuman repository defines a sophisticated memory stack designed for AI agent applications. Understanding the layered architecture of the memory subsystem in OpenHuman is essential for developers extending the platform, integrating custom storage backends, or optimizing agent memory retrieval. Each layer enforces specific contracts and responsibilities, creating a pipeline that guards against abuse while remaining flexible enough to support pluggable memory providers.

The Ten Architectural Layers

1. Contract Layer (tinymemory-api)

The foundation of the stack resides in src/openhuman/memory/api.rs, which re-exports the tinymemory-api crate to ensure type consistency across process boundaries. This layer defines the wire protocol shared between the core runtime and any loaded native module.

Key types include MemoryError, Chunk, Capabilities, MemoryProvider, and MemoryEvent. By centralizing these definitions, OpenHuman guarantees that both the in-process engine and external modules speak the exact same language, preventing serialization mismatches at runtime.

2. Core Implementation Layer (memory/binding.rs)

When no external module is present, the system falls back to the default in-process memory engine implemented in src/openhuman/memory/binding.rs. The MemoryBinding::new() constructor initializes this store, and the type implements the MemoryProvider trait directly, providing concrete methods for store, retrieve, and diff operations. This layer serves as the baseline provider that higher-level APIs consume when dynamic modules are unavailable.

3. Guard & Policy Layer (memory/guard/)

Security and resource management are enforced at the boundary before any operation reaches the provider. Located in src/openhuman/memory/guard/, this layer comprises three critical components:

  • Policy (policy.rs): Validates permissions against read-only or full-access tiers.
  • Budget (budget.rs): Tracks token and byte usage to prevent runaway consumption.
  • Audit (audit.rs): Records access logs identifying who accessed what data and when.

By intercepting requests here, OpenHuman applies security, budgeting, and compliance policies universally, regardless of whether the underlying provider is the core binding or an external module.

4. Provider Selection Layer (memory/ops/provider.rs)

The routing logic in src/openhuman/memory/ops/provider.rs determines which concrete implementation handles a given request. At runtime, the system checks for the presence of a dynamic module. If detected, it instantiates ModuleMemoryProvider; otherwise, it routes to the fallback MemoryBinding. This selection happens transparently to the rest of the stack, allowing modules to replace core functionality without code changes elsewhere.

5. Synchronization Layer (memory/sync/)

To maintain consistency between the in-process store and external modules, src/openhuman/memory/sync/ implements bidirectional synchronization. The sync.rs file contains the reconciliation logic, while bus.rs implements the TinyBus-based event bus that propagates memory events across the core-module boundary. This ensures that writes originating in the module are reflected in the core (and vice versa) without manual cache management.

6. Query Layer (memory/query/)

High-level read operations for agents and UI components are abstracted in src/openhuman/memory/query/. This layer exposes tree-traversal utilities such as:

  • cover_window: Builds a windowed view of the memory graph.
  • drill_down and fast_walk: Navigate hierarchical chunk relationships.
  • fetch_leaves: Retrieves terminal nodes efficiently.
  • search_entities: Performs full-text search across stored chunks.
  • ingest_document: Pipelines PDF, DOCX, and other formats into the graph.

These functions provide the semantic retrieval interface that agents use to surface relevant context during turns.

7. Operations Layer (memory/ops/)

Domain-specific write operations and manipulations reside in src/openhuman/memory/ops/. Unlike the Query Layer, which focuses on retrieval, this layer handles mutations and business logic:

  • tool_memory.rs: Interfaces for agent tools to read/write memory.
  • learn.rs: Manages embedding generation and learning-related updates.
  • kv_graph.rs: Handles key-value graph manipulations.
  • files.rs: Provides file-based import/export helpers.

These operations sit atop the raw provider calls, adding context-aware logic before persisting changes.

8. Agent-Facing Layer (memory/agent/)

The runtime interface used specifically by the OpenHuman agent system is defined in src/openhuman/memory/agent/. The ops.rs file exposes high-level functions like read_memory and write_memory that respect the agent’s current policy context, while tools.rs defines the schema of memory tools surfaced directly in agent prompts. This layer translates agent intentions into guarded provider calls.

9. Host Integration Layer (memory/host.rs)

Bridging the core runtime with the dynamic module system (src/openhuman/modules/), this layer consists of host.rs and host_impls.rs. The MemoryHost struct implements the TinyBus contract for the module side, and host_impls.rs contains the concrete logic that forwards calls to the selected provider. When an external module is active, this layer marshals requests across the process boundary while maintaining the same tinymemory-api contract.

10. Schema & RPC Layer (memory/schema/)

The external interface for frontend clients and external services is defined in src/openhuman/memory/schema/ and rpc_models.rs. This layer structures the JSON-RPC schemas exposed over the network, with schema/mod.rs aggregating type definitions and rpc_models.rs defining request/response structs for endpoints like memory_search. All RPC calls ultimately invoke the same guarded provider stack, ensuring consistency with internal agent calls.

Data Flow Across the Stack

A typical memory operation traverses the layers in a strict sequence:

  1. Agent Turn → Agent Ops: The runtime calls functions in memory/agent/ops.rs (e.g., read_memory).
  2. Guard → Provider: The request passes through the Guard layer (policy.rs + budget.rs) for validation.
  3. Provider Selection: memory/ops/provider.rs selects either MemoryBinding or ModuleMemoryProvider.
  4. Execution: The selected provider executes the low-level operation defined in the tinymemory-api contract. For modules, memory/host forwards the call over TinyBus.
  5. Synchronization: The Sync layer propagates changes bidirectionally between core and module stores via the event bus.
  6. Query/Ops: Higher-level utilities in memory/query/ and memory/ops/ build on provider results to return structured data.
  7. Schema/RPC: Frontend requests follow the same path after marshaling through the JSON-RPC layer.

This flow ensures that security, budgeting, and extensibility are enforced once at the guard and provider layers, while the rest of the system consumes a clean, high-level API.

Implementation Examples

Agent Reading Memory

use openhuman::memory::agent::ops::read_memory;
use openhuman::memory::guard::policy::MemoryPolicy;

// Inside an agent tool implementation
let policy = MemoryPolicy::full(); // respect the agent's tier
let chunks = read_memory(&policy, "user:123", "topic:travel")
    .await
    .expect("failed to read memory");

// `chunks` holds the retrieved `Chunk` structs

Source: [memory/agent/ops.rs](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/agent/ops.rs)

Loading a Native Memory Module

use openhuman::memory::host::MemoryHost;
use openhuman::modules::registry::ModuleRegistry;

// Register a module (e.g., `tinymemory-module` v0.3.1)
let registry = ModuleRegistry::default();
let module = registry
    .load("tinymemory-module", "0.3.1")
    .expect("module not found");

// The host exposes the same contract over TinyBus
let host = MemoryHost::new(module);
host.start_sync(); // begins bidirectional sync with core

Source: [memory/host_impls.rs](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/host_impls.rs)

UI Query via JSON-RPC

import { coreRpcClient } from "./services/coreRpcClient";

async function searchMemory(query: string) {
  const resp = await coreRpcClient.call("memory_search", { query });
  // `resp` contains an array of matching chunks
  return resp.results;
}

// Usage in a React component
const results = await searchMemory("Paris travel itinerary");

Source: [memory/rpc_models.rs](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/rpc_models.rs)

Key Files Reference

Layer File / Directory Purpose
Contract src/openhuman/memory/api.rs Re-exports tinymemory-api types (MemoryProvider, Chunk).
Core Binding src/openhuman/memory/binding.rs Default in-process engine (MemoryBinding).
Guard src/openhuman/memory/guard/policy.rs & budget.rs Permission and budget enforcement.
Provider Selection src/openhuman/memory/ops/provider.rs Router between core and module providers.
Sync src/openhuman/memory/sync/sync.rs & bus.rs Bidirectional consistency via TinyBus.
Query src/openhuman/memory/query/cover_window.rs Graph traversal and search utilities.
Operations src/openhuman/memory/ops/tool_memory.rs Domain-specific memory actions.
Agent API src/openhuman/memory/agent/ops.rs Agent turn memory access.
Host Bridge src/openhuman/memory/host.rs & host_impls.rs Dynamic module integration.
RPC & Schema src/openhuman/memory/schema/mod.rs JSON-RPC definitions for frontend.

Summary

  • OpenHuman’s memory subsystem uses a strictly layered architecture with ten distinct levels of abstraction.
  • The Contract Layer (tinymemory-api) ensures type safety between core and modules.
  • Guard & Policy Layer enforces security and budgets universally before any provider execution.
  • Provider Selection enables hot-swappable storage backends without altering business logic.
  • Synchronization maintains consistency between in-process and external module stores via TinyBus.
  • Query and Operations Layers separate read-heavy graph traversal from write-heavy domain logic.
  • All external interfaces (Agent, UI) converge on the same guarded provider stack, ensuring consistent behavior.

Frequently Asked Questions

How does OpenHuman enforce security and budget constraints in memory operations?

The Guard & Policy Layer in src/openhuman/memory/guard/ intercepts every request before it reaches the provider. Specifically, policy.rs validates read/write permissions against access tiers, while budget.rs tracks token and byte consumption to prevent abuse. This architecture ensures that constraints apply uniformly whether the operation originates from an internal agent or an external RPC call.

Can external modules completely replace the default in-process memory engine?

Yes, the Provider Selection Layer (src/openhuman/memory/ops/provider.rs) supports runtime substitution of the memory backend. When a module such as tinymemory-module is loaded via the ModuleRegistry, the system instantiates ModuleMemoryProvider and routes all calls through the Host Integration Layer over TinyBus, bypassing the default MemoryBinding entirely.

How does the synchronization layer maintain consistency between core and module stores?

The Synchronization Layer utilizes src/openhuman/memory/sync/sync.rs for bidirectional reconciliation logic and bus.rs for the TinyBus event bus. When a write occurs in either the core or the module, the event bus propagates the change across the process boundary, ensuring both stores remain synchronized without requiring explicit locks or manual cache invalidation.

What distinguishes the Query Layer from the Operations Layer?

The Query Layer (src/openhuman/memory/query/) focuses on read-only retrieval patterns, exposing utilities like cover_window and search_entities for graph traversal and full-text search. In contrast, the Operations Layer (src/openhuman/memory/ops/) handles stateful mutations and business logic, such as learn.rs for embedding updates and tool_memory.rs for agent tool interactions, effectively separating read optimization from write complexity.

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 →