# How the Obsidian Vault Synchronizes with the OpenHuman Memory Tree Canonicalization Process

> Learn how OpenHuman synchronizes an Obsidian vault with its memory tree canonicalization. Discover bidirectional sync for seamless data alignment.

- Repository: [Tiny Humans/openhuman](https://github.com/tinyhumansai/openhuman)
- Tags: how-to-guide
- Published: 2026-05-12

---

**OpenHuman maintains bidirectional synchronization between its SQLite memory-tree and an Obsidian-compatible markdown vault by writing canonicalized chunks and summaries to `<workspace>/wiki/` during the canonicalization pipeline, then re-ingesting user edits on subsequent runs to keep both stores aligned.**

The OpenHuman platform employs a dual-storage architecture that bridges machine-readable databases with human-readable knowledge bases. When the system performs **memory tree canonicalization**—the process of scoring, summarizing, and hierarchically organizing extracted knowledge—it simultaneously updates an **Obsidian vault** that serves as a browsable mirror of the agent's memory. This synchronization ensures that every canonical chunk and summary node exists both in the authoritative SQLite store and in a local markdown vault accessible through Obsidian's graph view.

## Ingestion Pipeline: From Raw Sources to Canonical Chunks

The synchronization process begins during the ingestion phase, where OpenHuman parses external sources such as Gmail, Slack, and WhatsApp into standardized memory chunks. Provider-specific modules like `gmail::ingest.rs` and `slack::ingest.rs` handle the initial parsing, converting raw messages into **canonical chunks** of ≤ 3 k tokens formatted as Markdown.

These chunks are stored in the SQLite `chunks` table while simultaneously being written to the Obsidian vault. The job orchestration in [`src/openhuman/memory/tree/jobs/handlers/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/jobs/handlers/mod.rs) coordinates this dual-write operation:

- [`src/openhuman/composio/providers/gmail/ingest.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/composio/providers/gmail/ingest.rs) (line 404) writes markdown files for Obsidian compatibility
- [`src/openhuman/composio/providers/slack/ingest.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/composio/providers/slack/ingest.rs) (line 227) performs similar vault writes for Slack messages

## Tag Generation and YAML Header Updates

After chunk creation, OpenHuman generates **Obsidian-style hierarchical tags** using the `kind/Value` format to enable graph navigation and filtering. The tag logic resides in [`src/openhuman/memory/tree/content_store/tags.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/tags.rs), where two key functions operate:

- `entity_tag` constructs the hierarchical `kind/Value` string
- `update_chunk_tags` atomically rewrites the `tags:` block in the markdown file's YAML front-matter while preserving the body content's SHA hash

As documented in [`src/openhuman/memory/tree/content_store/README.md`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/README.md), this process ensures that metadata updates don't corrupt the underlying content while maintaining compatibility with Obsidian's tag explorer and graph view.

## Canonical Summary Trees and Wikilink Construction

During **canonicalization**, the system folds multiple chunks into higher-level summary nodes, creating a hierarchical memory tree. This process generates **summary markdown files** that serve as parent nodes in the Obsidian vault, containing:

- YAML front-matter with child wikilinks (`[[<basename>]]`) referencing descendant chunks
- Obsidian-compatible `tags:` sections for hierarchical filtering

The markdown composition logic in [`src/openhuman/memory/tree/content_store/compose.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/compose.rs) handles this construction:

- Line 49 builds the canonical source tag for summaries
- Line 388 adds child wikilinks to the front-matter
- Filename safety is ensured via [`memoryTree.ts`](https://github.com/tinyhumansai/openhuman/blob/main/memoryTree.ts) (line 447) in the UI layer, which sanitizes basenames for filesystem compatibility

## Vault Layout and File System Operations

All markdown files reside under a single **content root** defined in [`src/openhuman/memory/tree/content_store/paths.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/paths.rs). The vault uses a flat directory structure at `<workspace>/wiki/` with subfolders for each logical source (`source/<slug>/`), avoiding deep hierarchies that would clutter the Obsidian sidebar (see [`paths.rs`](https://github.com/tinyhumansai/openhuman/blob/main/paths.rs) line 46).

The actual filesystem operations are coordinated by [`src/openhuman/memory/tree/content_store/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/mod.rs), which ensures exactly one copy of each chunk exists in the vault. The dedicated Obsidian writer in [`src/openhuman/memory/tree/content_store/obsidian.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/obsidian.rs) serves as the primary entry point for vault writes, abstracting the specifics of markdown formatting and file placement. The abstraction for source-file handling, including Obsidian ".base" file representations, is provided by [`src/openhuman/memory/tree/tree_source/source_file.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/tree_source/source_file.rs).

## UI Deep-Link Integration

The React frontend provides seamless navigation between the OpenHuman interface and Obsidian through **deep-link integration**. The RPC read path in [`src/openhuman/memory/tree/read_rpc.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/read_rpc.rs) exposes the vault's content location to the frontend, enabling the construction of valid filesystem paths.

When users click "View vault in Obsidian," the application constructs an `obsidian://open?path=…` URL that the operating system resolves to the local Obsidian installation.

Implementation details appear in two key UI components:

- [`app/src/components/intelligence/MemoryWorkspace.tsx`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/components/intelligence/MemoryWorkspace.tsx) contains the `openVaultInObsidian` function (lines 70‑75) that opens the entire vault
- [`app/src/components/intelligence/MemoryGraph.tsx`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/components/intelligence/MemoryGraph.tsx) implements `openSummaryInObsidian` for individual node navigation
- [`app/src/utils/tauriCommands/memoryTree.ts`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/utils/tauriCommands/memoryTree.ts) provides filesystem-safe basename generation for URLs

The following TypeScript implementation demonstrates the vault opening mechanism:

```typescript
async function openVaultInObsidian(contentRootAbs: string): Promise<void> {
  const url = `obsidian://open?path=${encodeURIComponent(contentRootAbs)}`;
  console.debug('[ui-flow][memory-workspace] open vault in Obsidian url=%s', url);
  await window.__TAURI__.invoke('open', { path: url });
}

```

Both functions log deep-link URLs using prefixed debug markers (`[ui-flow][memory-workspace]` and `[memory-graph]`) for troubleshooting synchronization issues.

## Bidirectional Synchronization Cycle

The synchronization operates as a **one-way write, round-trip read** system where SQLite remains the single source of truth. When users edit markdown files directly in Obsidian, changes are not immediately written back to the database. Instead, the next canonicalization run detects modifications through **filesystem timestamp** comparisons.

The re-ingestion process follows this sequence:

1. The scanner identifies modified files by comparing timestamps against the last canonicalization run
2. The markdown parser re-extracts entities and content from the edited file
3. The corresponding chunk row in SQLite updates to reflect the changes
4. The system regenerates tags and summary links, ensuring the vault and memory-tree converge to a consistent state

This design guarantees that the **SQLite memory-tree** maintains authoritative status while the Obsidian vault serves as a reproducible, human-editable view that automatically reconciles with the canonical state.

## Summary

- **Dual storage architecture**: OpenHuman maintains both an SQLite memory-tree and an Obsidian-compatible markdown vault at `<workspace>/wiki/`
- **Canonicalization writes**: The pipeline in `src/openhuman/memory/tree/content_store/` handles markdown generation, tag creation, and summary tree construction during the canonicalization process
- **Hierarchical tags**: The system generates `kind/Value` tags via [`src/openhuman/memory/tree/content_store/tags.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/tags.rs) for Obsidian graph navigation
- **Deep-link support**: UI components in `app/src/components/intelligence/` enable one-click vault opening via `obsidian://` URLs
- **Bidirectional sync**: User edits in Obsidian are detected via filesystem timestamps and re-ingested on subsequent canonicalization runs, with SQLite serving as the single source of truth

## Frequently Asked Questions

### How does OpenHuman handle filename collisions in the Obsidian vault?

The system prevents collisions through [`app/src/utils/tauriCommands/memoryTree.ts`](https://github.com/tinyhumansai/openhuman/blob/main/app/src/utils/tauriCommands/memoryTree.ts) (line 447), which sanitizes basenames to ensure filesystem safety. Additionally, [`src/openhuman/memory/tree/content_store/paths.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/paths.rs) organizes files into source-specific subdirectories (`source/<slug>/`), reducing the likelihood of naming conflicts between different data providers.

### Can I edit files in the Obsidian vault without breaking the synchronization?

Yes. The vault is designed for human editing, and any modifications made in Obsidian are detected during the next canonicalization cycle via filesystem timestamp checks. The re-ingestion process in [`src/openhuman/memory/tree/content_store/mod.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/mod.rs) parses your edits and updates the corresponding SQLite chunks, preserving the bidirectional flow without requiring manual intervention.

### What happens if the Obsidian vault directory is moved or deleted?

The vault is a derived view of the SQLite memory-tree, not the primary data store. If deleted, OpenHuman regenerates the entire vault from the canonical memory-tree during the next canonicalization run. However, any un-ingested edits made in Obsidian would be lost, as the system cannot recover changes that never completed a synchronization cycle back to SQLite.

### Which component generates the hierarchical tags visible in Obsidian's graph view?

Tag generation occurs in [`src/openhuman/memory/tree/content_store/tags.rs`](https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/memory/tree/content_store/tags.rs), specifically through the `entity_tag` and `update_chunk_tags` functions. These create the `kind/Value` hierarchical format that Obsidian recognizes for graph visualization and tag filtering, automatically updating the YAML front-matter of vault files without altering the body content.