# Core Architecture of ai-memory: A Dual-Layer Memory System for AI Agents

> Explore the core architecture of ai-memory, a dual-layer system using markdown files as truth and SQLite for fast retrieval. Understand its eight-crate design.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: architecture
- Published: 2026-09-09

---

**The ai-memory system implements a dual-layer architecture where markdown files serve as the single source of truth while a SQLite index provides fast retrieval, organized into eight single-responsibility crates that communicate through strict typed APIs and invariants.**

The ai-memory project by akitaonrails is a local-first memory system designed for AI agents and developer workflows. Understanding the core architecture of ai-memory reveals how it balances durability, searchability, and auditability without requiring external LLM providers by default.

## Dual-Layer Storage Model

The foundation of ai-memory rests on a strict separation between authoritative storage and derived indices.

### Markdown Wiki as Source of Truth

All knowledge persists as markdown files in `<data_dir>/wiki/`. This layer remains the **authoritative** representation of memory through several mechanisms:

- **Atomic writes**: All file operations use a temporary file + rename + fsync pattern to guarantee crash safety
- **Git versioning**: The `ai-memory-wiki` crate integrates `git2` for automatic versioning of all changes
- **Human-readable**: Files remain accessible via standard text editors and command-line tools

As documented in [`docs/ARCHITECTURE.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/ARCHITECTURE.md), writes to the wiki layer trigger corresponding updates to the derived index, never the reverse.

### SQLite-Driven Derived Index

The `<data_dir>/db/memory.sqlite` database mirrors the wiki for high-performance access patterns:

- **WAL mode**: SQLite operates in Write-Ahead Logging mode for concurrent read performance
- **Single-writer actor**: The `ai-memory-store` crate implements an actor pattern where a single connection owns all writes, eliminating race conditions
- **Rich metadata**: Stores embeddings, session observations, handoffs, and cross-project link graphs

The `ReaderPool` in [`crates/ai-memory-store/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/lib.rs) manages a pool of read-only connections for query operations, while the writer actor序列所有 mutations.

## Modular Crate Architecture

The codebase organizes into eight independent crates under `crates/`, each enforcing a single responsibility:

- **`ai-memory-core/`**: Domain types, IDs, and error variants—**zero I/O operations**
- **`ai-memory-store/`**: SQLite writer actor, reader pool connection management, and decay mathematics
- **`ai-memory-wiki/`**: Atomic markdown writes, file-watcher implementation, and Git handling
- **`ai-memory-mcp/`**: RMCP transport layer, tool routing, and admin HTTP endpoints
- **`ai-memory-hooks/`**: Hook payload schemas, sanitization logic, and the `/hook` endpoint handler
- **`ai-memory-llm/`**: Provider authentication, `LlmProvider` and `Embedder` trait definitions
- **`ai-memory-consolidate/`**: Karpathy-style ingestion pipeline, linting, and auto-improvement scheduling
- **`ai-memory-workstream/`**: Read-only native transcript adapters and launch integrations
- **`ai-memory-cli/`**: The `ai-memory` binary entry point and subcommand dispatch in [`src/main.rs`](https://github.com/akitaonrails/ai-memory/blob/main/src/main.rs)

Each crate exposes typed APIs; no crate accesses another's internal data structures directly. This enforces cross-cutting invariants like "typed 3-tuple identity" (`workspace_id`, `project_id`, `path`) and single configuration paths.

## Steady-State Data Flow

The system processes agent observations through a six-stage pipeline:

1. **Lifecycle hook**: External agent CLIs POST JSON events to `/hook` with a strict ≤200ms timeout (fire-and-forget)
2. **Sanitization**: The `ai-memory-hooks` sanitiser acts as the **only trust boundary** between untrusted input and storage
3. **WriteCmd enqueue**: Sanitized observations route to the writer actor, which persists to SQLite and creates wiki pages when necessary
4. **Session termination**: On `session-end` events, the server synthesizes `sessions/<id>.md`, creates handoff rows, and commits wiki updates atomically
5. **LLM consolidation**: If `AI_MEMORY_LLM_PROVIDER` is configured, `memory_consolidate` rewrites summaries into richer conceptual pages (`concepts/`, `decisions/`)
6. **Auto-improvement**: Background jobs in `ai-memory-consolidate` review completed sessions and generate proposals through the standard wiki mutation path

This flow ensures all edits remain auditable through Git history while supporting real-time agent integrations.

## Multi-Stream Retrieval Pipeline

The `memory_query` function implements **Reciprocal Rank Fusion (RRF)** across four parallel search streams:

| Stream | Index Type | Search Target |
|--------|-----------|---------------|
| **FTS5** | Full-text | Page titles and bodies |
| **Entity** | Front-matter | `entities` list in YAML headers |
| **Link-neighbour** | Graph | Wikilink relationships |
| **Vector** | Cosine similarity | Embedding space (when `Embedder` configured) |

Results merge with **authority multipliers**based on tier (Working, Episodic, Semantic, Procedural), pinned status, and calculated salience. When `AI_MEMORY_RERANKER=llm` is set, a final LLM-based reranking pass reorders the result set.

## Memory Tiers and Decay System

Pages categorize into four lifecycle tiers, each with distinct retention policies:

- **Working**: Active session data with short TTL
- **Episodic**: Past session summaries
- **Semantic**: Conceptual knowledge and decisions
- **Procedural**: How-to guides and instructions

A periodic **forget sweep** (implemented in `ai-memory-store`) applies tier-specific decay formulas, evicts cold pages, hard-deletes TTL-expired entries, and prunes raw observations while **pinned pages** remain exempt from all decay.

## Security and Cross-Cutting Invariants

The architecture enforces strict invariants at the type system level:

- **Single-writer SQLite**: Prevents concurrent write transactions entirely
- **Sanitiser isolation**: Only path from untrusted hook data to storage
- **Atomic wiki operations**: Guarantees filesystem consistency via `fsync`
- **Typed IDs**: Every row enforces `workspace_id`, `project_id`, and `path` as a composite key
- **Zero-LLM default**: Core functionality works without any `AI_MEMORY_LLM_PROVIDER` configured

These invariants are enumerated in [`docs/ARCHITECTURE.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/ARCHITECTURE.md) under *Cross-cutting invariants*.

## Summary

- **ai-memory** uses a dual-layer design with markdown as the source of truth and SQLite for fast access
- Eight single-responsibility crates in `crates/` enforce strict API boundaries and typed IDs
- The single-writer actor pattern in `ai-memory-store` eliminates SQLite concurrency issues
- **RRF retrieval** combines FTS5, entity matching, link graphs, and optional vector similarity
- Memory tiers with decay formulas and pinned exemptions manage storage lifecycle
- All mutations flow through the wiki layer, ensuring Git-auditable history without LLM dependencies

## Frequently Asked Questions

### How does ai-memory ensure consistency between the markdown wiki and SQLite index?

All writes originate in the wiki layer through atomic file operations (tmp + rename + fsync) in `ai-memory-wiki`, then propagate to the SQLite index via the single-writer actor in `ai-memory-store`. The wiki remains the authoritative source; the database is purely a derived view. If the database corrupts, it can rebuild entirely from the markdown files.

### What is the single-writer actor pattern used in ai-memory-store?

The `ai-memory-store` crate implements an actor pattern where one dedicated connection handles all write operations through a message queue. This design eliminates SQLite's "database is locked" errors without complex retry logic, while a separate `ReaderPool` manages multiple read-only connections for concurrent queries.

### Can ai-memory function without connecting to an LLM provider?

Yes. The system operates in **zero-LLM default** mode. All core features—wiki storage, SQLite indexing, session tracking, and decay management—work without any `AI_MEMORY_LLM_PROVIDER` configuration. LLM integration only enables optional features like semantic search embeddings, consolidation rewriting, and LLM-based result reranking.

### How does cross-project linking work in the wiki architecture?

Wikilinks support the syntax `[[project:path.md]]` to reference pages across workspaces. The wiki parser extracts a `LinkTarget { workspace, project, path }` struct, and the store records these with `to_workspace` and `to_project` columns. This enables a global dependency graph while maintaining scope isolation, allowing agents to trace relationships across project boundaries without namespace collisions.