OpenHuman Memory Management: Understanding Memory Tree, Obsidian Sync, and TinyMemory

OpenHuman memory management unifies AI-generated content into a virtual Memory Tree backed by the TinyMemory engine, with optional two-way synchronization to Obsidian vaults via background RPC pipelines.

OpenHuman memory management serves as the persistent backbone for the tinyhumansai/openhuman project, storing every AI interaction in a hierarchical structure that bridges local storage and external knowledge bases. The architecture combines a virtual Memory Tree with the TinyMemory versioned key-value engine, while providing seamless Obsidian sync capabilities for users who prefer markdown-based knowledge management.

Memory Tree Architecture

The Memory Tree presents a unified "file-system-like" namespace that aggregates multiple specialized storage domains. Rather than storing files directly, it maintains a virtual hierarchy over documents, chunks, goals, and people data.

Virtual Hierarchy and Domain Stores

Each data type registers with the central DomainSet in src/core/all.rs, allowing the tree to materialize paths on demand. Domain-specific stores handle concrete persistence for their respective data types:

  • Documents → store::documents
  • Chunks → store::chunks
  • Goals and People → dedicated schema stores

The public façade in src/openhuman/memory/mod.rs routes queries to appropriate sub-modules without requiring core-wide refactoring when adding new domains.

TinyMemory Engine

All domains ultimately persist through the TinyMemory engine, a versioned key-value store vendored at vendor/tinymemory/crates/tinymemory-core. This engine provides atomic writes and transactional batch updates while maintaining a minimal footprint.

The contract crate tinymemory-api defines the wire protocol including MemoryProvider, Chunk, and Error types. src/openhuman/memory/api.rs re-exports these definitions to guarantee type consistency between the core and dynamically loaded modules:

// src/openhuman/memory/api.rs
pub use tinymemory_api::*;

Tree Runtime Operations

The Tree Runtime in src/openhuman/memory/tree/tree_runtime/ops.rs implements operations such as list, read, and sync. These operations resolve virtual paths to physical storage locations and expose an RPC interface for tooling integration.

Obsidian Vault Integration

OpenHuman can treat the Memory Tree as an Obsidian vault, enabling users to browse AI-generated content in Obsidian while the system maintains bidirectional synchronization.

Vault Detection Logic

Detection begins in src/openhuman/memory/obsidian_registry.rs, which walks the filesystem searching for obsidian.json files. The system checks whether the content root (defaulting to ~/OpenHuman/projects) or any ancestor directory appears in the Obsidian registry:

// src/openhuman/memory/obsidian_registry.rs
pub fn is_registered_vault(
    content_root: &Path, 
    extra_config_dir: Option<&Path>
) -> Result<bool, std::io::Error> {
    // …search for obsidian.json, parse, compare paths…
}

Users may specify an override via the extra_config_dir parameter to support non-standard Obsidian installations.

RPC Endpoints and UI Integration

The obsidian_vault_status endpoint in src/openhuman/memory/read_rpc/vault.rs returns structured status information enabling the React UI to render "Open in Obsidian" buttons:

// src/openhuman/memory/read_rpc/vault.rs
pub async fn obsidian_vault_status(
    ctx: &mut RpcContext,
) -> Result<RpcOutcome<ObsidianVaultStatusResponse>, String> {
    // …spawn blocking task that calls is_registered_vault…
}

When a vault is detected, the UI generates deep-links using the obsidian://open?path= protocol with the absolute vault path returned by the registry.

Auto-Sync Pipeline

Background synchronization is controlled by the memory_tree_auto_sync platform setting. When enabled, the Memory Sync service (src/openhuman/memory/sync/mod.rs) periodically executes the memory_tree_sync_status RPC defined in src/openhuman/memory/sync/sync_status/rpc.rs. This aggregates health information from all sub-domains—including paused states, error flags, and job counters—into a compact payload for UI consumption.

TinyMemory Storage Implementation

The TinyMemory engine provides the foundational persistence layer for all memory operations. It stores versioned chunks optimized for append-heavy AI conversation patterns.

Contract and Type Safety

Type safety across module boundaries is enforced through the tinymemory-api contract crate. By re-exporting these types in src/openhuman/memory/api.rs, the system ensures that modules compiled against the contract can load at runtime without type mismatches, preventing serialization errors between the core and extensions.

MemoryHost Wrapper

The MemoryHost struct in src/openhuman/memory/host.rs provides high-level helpers for the core:

  • write_chunk: Atomic single-record writes
  • read_chunk: Version-aware retrieval
  • Transaction-style batch updates for multi-domain consistency

End-to-End Sync Pipeline

The complete data flow from external sources to Obsidian follows four stages:

  1. Source Ingestion: Connectors (Composio, ClickUp, Slack) push data via RPC controllers in src/openhuman/memory/sync/composio/*
  2. Tree Updates: The event bus notifies the Tree Runtime of store-level changes, updating the virtual hierarchy
  3. Health Aggregation: The sync status RPC collates per-domain health flags
  4. Deep Link Generation: If a vault is registered, the UI constructs obsidian:// URLs for instant navigation

All operations are asynchronous and governed by the agent-policy system, ensuring background sync never blocks user-initiated turns.

Practical Code Examples

The following examples demonstrate interacting with the memory system via the Rust API (see examples/run_turn.rs for complete context):

use openhuman_core::{Harness, Provider, Workspace, Access};

// Initialize core with ephemeral workspace
let harness = Harness::builder()
    .provider(Provider::openai_compatible(
        "https://api.openai.com".into(), 
        "sk-…".into()
    ))
    .workspace(Workspace::Ephemeral)
    .access(Access::full())
    .build()
    .await
    .expect("failed to build core");

// List Memory Tree root entries
let tree = harness
    .rpc()
    .call::<_, Vec<String>>("memory_tree_list", ())
    .await
    .expect("list failed");
println!("Memory Tree root entries: {:?}", tree);

Querying Obsidian vault status:

let vault_status = harness
    .rpc()
    .call::<_, openhuman::memory::read_rpc::ObsidianVaultStatusResponse>(
        "obsidian_vault_status",
        (),
    )
    .await
    .expect("vault query failed");

if vault_status.is_registered {
    println!("Vault path: {}", vault_status.absolute_path);
}

Enabling automatic synchronization for external connections:

harness
    .rpc()
    .call::<_, ()>("memory_tree_auto_sync_set", ("clickup", true))
    .await
    .expect("failed to enable sync");

Summary

  • Memory Tree provides a virtual hierarchy unifying documents, chunks, goals, and people data under a single namespace rooted at ~/OpenHuman/projects
  • TinyMemory serves as the versioned key-value engine backing all domains, with type safety enforced through the tinymemory-api contract
  • Obsidian sync enables bidirectional workflows through automatic vault detection via obsidian.json and deep-link generation
  • The Tree Runtime in tree/tree_runtime/ops.rs materializes virtual paths on demand while the Sync Service manages background data flows
  • All operations are accessible via RPC endpoints, allowing external tools and UI components to interact with the memory layer without direct file system access

Frequently Asked Questions

How does the Memory Tree differ from a regular file system?

The Memory Tree is a virtual hierarchy that aggregates multiple specialized stores rather than storing files directly. According to the tinyhumansai/openhuman source code, it maps paths to domain-specific stores (documents, chunks, goals) registered in the DomainSet, with actual persistence handled by the TinyMemory engine. This allows the system to present a unified namespace while optimizing storage for each data type.

What triggers Obsidian vault detection in OpenHuman?

Detection occurs when the obsidian_vault_status RPC endpoint calls is_registered_vault in src/openhuman/memory/obsidian_registry.rs. The function walks the filesystem looking for obsidian.json files and checks whether the content root (or any ancestor directory) matches a registered vault path. Users can override the search path via the extra_config_dir parameter.

Can I disable automatic synchronization with external services?

Yes. The memory_tree_auto_sync platform setting controls background synchronization. You can disable specific connectors by calling the memory_tree_auto_sync_set RPC with false, or prevent the sync service from scheduling jobs entirely. The agent-policy system ensures that even when enabled, background sync yields to user-initiated operations.

How does TinyMemory ensure data consistency across modules?

TinyMemory enforces a single source of truth through the contract crate pattern. The tinymemory-api crate defines all types and protocols, which src/openhuman/memory/api.rs re-exports to both the core and loaded modules. This guarantees that modules compiled against the contract use identical type definitions, preventing runtime serialization mismatches when chunks are written by one component and read by another.

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 →