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

> Discover the core architecture of ai-memory, a dual-layer system using a markdown wiki and SQLite index. Explore its efficient Rust crate design for AI agents.

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

---

**The core architecture of ai-memory is a dual-layer system that uses a markdown wiki as the single source of truth and a SQLite-driven index for fast retrieval, organized into 8 independent Rust crates with strict single-responsibility boundaries.**

The **ai-memory** project by akitaonrails implements a persistent memory layer for AI agents. Its architecture prioritizes durability, auditability, and retrieval performance through a clear separation between human-readable storage and machine-optimized indexing.

## Dual-Layer Data Model

The foundation of ai-memory rests on two distinct storage layers that remain synchronized through controlled write paths.

### Wiki Layer: The Source of Truth

All knowledge lives as markdown files in `<data_dir>/wiki/`. This design choice guarantees that your memory remains human-inspectable and version-controllable.

Key characteristics:

- **Atomic writes** — every mutation uses a temporary file, rename, and `fsync` sequence
- **Git versioning** — powered by `git2` for complete audit history
- **Authoritative state** — the wiki is the ground truth; the database is a derived view

### SQLite Index: The Fast Mirror

The derived index at `<data_dir>/db/memory.sqlite` enables efficient search and metadata queries.

Critical implementation details:

- **WAL mode** for concurrent reads during writes
- **Single-writer actor** owns the write connection, eliminating race conditions
- Mirrors sessions, observations, handoffs, embeddings, and link graphs

This pattern appears in [`crates/ai-memory-store/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/lib.rs), where the writer actor enforces sequential consistency without locks.

## Crate Layout and Responsibility Boundaries

The codebase follows a strict **vertical slice** organization. Each crate has exactly one reason to change and communicates only through typed APIs.

| Crate | Responsibility | I/O Status |
|-------|---------------|------------|
| `ai-memory-core` | Domain types, IDs, errors | **No I/O** |
| `ai-memory-store` | SQLite writer actor, reader pool, decay math | Database I/O |
| `ai-memory-wiki` | Atomic markdown writes, file-watcher, Git handling | Filesystem I/O |
| `ai-memory-mcp` | RMCP transport, tool router, admin routes | Network I/O |
| `ai-memory-hooks` | Hook payload schemas, sanitiser, `/hook` endpoint | Network I/O |
| `ai-memory-llm` | Provider auth, `LlmProvider` / `Embedder` traits | External API |
| `ai-memory-consolidate` | Karpathy-style ingest, lint, auto-improve pipeline | Pipeline I/O |
| `ai-memory-workstream` | Read-only native transcript + launch adapters | Filesystem I/O |
| `ai-memory-cli` | `ai-memory` binary entry point | All orchestrated |

This structure prevents direct data structure coupling. A crate cannot bypass another's API to touch internal state.

## Steady-State Data Flow

The core architecture of ai-memory processes agent lifecycle events through a deterministic pipeline.

### 1. Lifecycle Hook Reception

Agent CLIs post JSON events to `POST /hook`. This endpoint is **fire-and-forget** with a hard **200 ms timeout** — the system never blocks agents.

### 2. Payload Sanitisation

The hook router in `ai-memory-hooks` performs the **sole trust boundary transformation**. Untrusted input is validated and normalized here exclusively.

### 3. Write Actor Enqueue

Sanitized observations become `WriteCmd` messages dispatched to the single-writer actor. The actor:

- Persists to SQLite
- Creates or updates wiki pages when session summaries are needed

### 4. Session Completion

On `session-end` events, the system:

- Synthesizes `sessions/<id>.md`
- Creates a **handoff** row for context continuity
- Commits the wiki update atomically

### 5. Optional LLM Consolidation

When `AI_MEMORY_LLM_PROVIDER` is configured, `memory_consolidate` from `ai-memory-consolidate` rewrites summaries into richer structures:

```

concepts/
decisions/
procedures/

```

### 6. Auto-Improvement Background Jobs

The scheduler in `ai-memory-consolidate` reviews completed sessions, generates improvement proposals via LLM, and writes them through the standard wiki path — maintaining full auditability.

Example scheduler invocation:

```rust
// In a tokio task started by the server
ai_memory_auto_improve::scheduler::run(pool.clone()).await?;

```

## Retrieval Pipeline: Multi-Stream RRF

The `memory_query` system implements **Reciprocal Rank Fusion** across multiple search streams.

| Stream | Search Target | Implementation Location |
|--------|-------------|------------------------|
| **FTS5** | Page titles and bodies | SQLite FTS5 virtual table |
| **Entity match** | Front-matter `entities` list | Indexed entity column |
| **Link-neighbour** | Wikilink graph | `to_workspace` / `to_project` columns |
| **Vector (optional)** | Cosine similarity | When embedder configured |

Post-fusion, results are re-ranked using **authority multipliers**:

- Tier (Working > Episodic > Semantic > Procedural)
- Pinned status
- Computed salience

Optional **LLM reranker** activates with `AI_MEMORY_RERANKER=llm`.

Query example via MCP tool:

```json
{
  "tool": "memory_query",
  "arguments": {
    "q": "how to reset a project",
    "scopes": ["my-workspace/my-project"]
  }
}

```

## Memory Tiers and Decay System

Pages are categorized into four **lifetime tiers** with distinct decay formulas:

- **Working** — active session context, shortest decay
- **Episodic** — event sequences, medium decay
- **Semantic** — facts and concepts, slow decay
- **Procedural** — how-to knowledge, very slow decay

**Pinned pages** are exempt from all decay.

The **forget sweep** periodic job:

1. Evicts cold pages to archive
2. Hard-deletes TTL-expired pages
3. Prunes old raw observations

This logic resides in `crates/ai-memory-store` alongside the decay mathematics.

## Cross-Project Linking

Wikilinks support workspace-spanning references using the syntax `[[project:path.md]]`.

The parser extracts a structured `LinkTarget`:

```rust
LinkTarget {
    workspace: Option<String>,
    project: Option<String>,
    path: String,
}

```

Storage records include `to_workspace` and `to_project` columns, enabling global dependency graphs while maintaining scope isolation.

## Security and Cross-Cutting Invariants

The architecture of ai-memory enforces safety through structural constraints:

- **Single-writer SQLite** — prevents concurrent write corruption
- **Sanitiser-only inbound path** — all untrusted data flows through one validator
- **Atomic wiki operations** — crash-safe persistence guarantees
- **Typed 3-tuple identity** — `(workspace_id, project_id, path)` enforced in every row
- **Zero-LLM default** — fully functional without external AI providers

These invariants are documented in [`docs/ARCHITECTURE.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/ARCHITECTURE.md) and codified in the type system.

## Key Source Files

| Path | Purpose |
|------|---------|
| [`docs/ARCHITECTURE.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/ARCHITECTURE.md) | Human-readable architectural overview |
| [`crates/ai-memory-core/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/lib.rs) | Domain types with zero I/O |
| [`crates/ai-memory-store/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/lib.rs) | Writer actor and reader pool |
| [`crates/ai-memory-wiki/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/lib.rs) | Atomic markdown and Git |
| [`crates/ai-memory-mcp/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/lib.rs) | RMCP transport layer |
| [`crates/ai-memory-llm/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-llm/src/lib.rs) | Provider abstraction |
| [`crates/ai-memory-consolidate/src/lib.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-consolidate/src/lib.rs) | Auto-improvement pipeline |
| [`crates/ai-memory-cli/src/main.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/main.rs) | Binary entry point |

## Summary

- **Dual-layer design**: Markdown wiki as source of truth, SQLite for speed
- **Single-responsibility crates**: 8 specialized packages with typed APIs
- **Deterministic flow**: Hooks → sanitise → writer actor → wiki + index
- **Multi-stream retrieval**: FTS5, entities, links, and vectors with RRF fusion
- **Tiered decay**: Automatic lifetime management with pin exemptions
- **Zero-LLM baseline**: Works without external AI, enhanced when configured

## Frequently Asked Questions

### How does ai-memory prevent data corruption during crashes?

The wiki layer uses **atomic file operations**: write to temporary file, `fsync`, then rename into place. This guarantees that the filesystem always contains a complete, valid file — never a partially-written state. The SQLite layer uses WAL mode for similar durability guarantees.

### Can ai-memory work entirely offline without any LLM provider?

**Yes.** The system defaults to zero-LLM operation. All core functionality — storage, retrieval, session tracking — works without external AI. LLM features like `memory_consolidate` and auto-improvement are strictly optional enhancements activated by setting `AI_MEMORY_LLM_PROVIDER`.

### What prevents multiple agents from corrupting the SQLite database?

A **single-writer actor** pattern enforces sequential access. All write operations route through one asynchronous task that owns the write connection. Reader pools provide concurrent read access, but writes are strictly serialized without locks or conflicts.

### How does the retrieval ranking combine different search signals?

The `memory_query` implementation uses **Reciprocal Rank Fusion (RRF)** to merge FTS5, entity, link, and vector streams. Each stream produces ranked results; RRF computes a fused score that democratically combines rankings without requiring score calibration. Final re-ranking applies authority multipliers for tier, pinning, and salience.