Core Architecture of ai-memory: A Dual-Layer Memory System for AI Agents
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
fsyncsequence - Git versioning — powered by
git2for 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, 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:
// 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:
{
"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:
- Evicts cold pages to archive
- Hard-deletes TTL-expired pages
- 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:
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 and codified in the type system.
Key Source Files
| Path | Purpose |
|---|---|
docs/ARCHITECTURE.md |
Human-readable architectural overview |
crates/ai-memory-core/src/lib.rs |
Domain types with zero I/O |
crates/ai-memory-store/src/lib.rs |
Writer actor and reader pool |
crates/ai-memory-wiki/src/lib.rs |
Atomic markdown and Git |
crates/ai-memory-mcp/src/lib.rs |
RMCP transport layer |
crates/ai-memory-llm/src/lib.rs |
Provider abstraction |
crates/ai-memory-consolidate/src/lib.rs |
Auto-improvement pipeline |
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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →