ai‑memory Crates Explained: A Complete Guide to the 9 Rust Crate Architecture
The ai‑memory project is organized as a Rust workspace of nine independent crates—ai‑memory‑core, ai‑memory‑store, ai‑memory‑wiki, ai‑memory‑mcp, ai‑memory‑hooks, ai‑memory‑llm, ai‑memory‑consolidate, ai‑memory‑workstream, and ai‑memory‑cli—each with a single responsibility that together implement a long‑term memory service for coding agents.
The ai‑memory crates follow a strict separation of concerns documented in [docs/ARCHITECTURE.md](https://github.com/akitaonrails/ai-memory/blob/main/docs/ARCHITECTURE.md#L33-L45). Every crate exposes a typed public API and never reaches into another crate's internals, enforcing architectural invariants like single‑writer SQLite access and one source‑of‑truth for markdown files.
ai‑memory‑core: Domain Types and Pure Data Models
The ai‑memory‑core crate defines the foundational types used across the entire system. It contains no I/O operations—only pure data structures, error types, and identifier types.
Key types include PageId, WorkspaceId, NewObservation, and ActorContext. These types establish the domain vocabulary that all other crates depend on.
// From crates/ai-memory-core/src/lib.rs
use ai_memory_core::{PageId, WorkspaceId, NewObservation, ActorContext};
By isolating domain logic in this crate, ai‑memory ensures type safety and consistent semantics without circular dependencies.
ai‑memory‑store: SQLite Storage Layer with Single‑Writer Actor
The ai‑memory‑store crate manages all persistence. It implements a single‑writer actor pattern for SQLite operations, a read‑only connection pool, database migrations, and decay mathematics for memory relevance.
Core APIs include Store::open for initialization, WriterHandle for exclusive write access, and ReaderPool for concurrent reads. The crate also exposes auto_improve helper functions.
use ai_memory_store::Store;
use std::path::Path;
let data_dir = Path::new("/tmp/ai-memory-data");
let store = Store::open(data_dir).expect("failed to open store");
All database access flows through this crate—no other component opens SQLite connections directly.
ai‑memory‑wiki: Atomic Markdown Handling and Git Integration
The ai‑memory‑wiki crate serves as the authoritative source‑of‑truth for wiki pages. It provides atomic file operations, filesystem watching, and Git integration for versioned markdown storage.
Primary APIs include Wiki::write_page for atomic writes and extract_links for analyzing page relationships. This crate ensures that markdown files remain the ground truth regardless of database state.
use ai_memory_wiki::Wiki;
use ai_memory_core::{NewPage, PagePath, Tier};
let page = NewPage {
workspace_id: workspace_id,
project_id: project_id,
path: PagePath::new("notes/todo.md").unwrap(),
title: "TODO".into(),
body: "Add more tests".into(),
tier: Tier::Episodic,
frontmatter_json: serde_json::json!({}),
pinned: false,
links: vec![],
author_id: None,
expires_at: None,
entities: vec![],
};
Wiki::write_page(&data_dir, page).expect("write failed");
ai‑memory‑mcp: MCP Transport and Tool Router
The ai‑memory‑mcp crate implements the Model Context Protocol (MCP) transport layer. It exposes the memory service as a set of MCP tools that coding agents can invoke.
Tool definitions include memory_query for semantic search and memory_write_page for creating new pages. This crate bridges external AI systems with the internal memory operations.
use ai_memory_mcp::tools::memory_query;
let result = memory_query(
"search term",
None, // optional workspace
None, // optional project
Some(10), // limit
false, // include expired?
false, // explain?
).await?;
ai‑memory‑hooks: Incoming Event Sanitization
The ai‑memory‑hooks crate handles external events submitted to the /hook endpoint. It defines schemas for incoming payloads and sanitizes raw JSON into valid observations.
The Sanitizer type validates and normalizes hook payloads, producing NewObservation instances that downstream components can safely process.
use ai_memory_hooks::{Sanitizer, NewObservation, ObservationKind};
let raw = r#"{
"event": "session-start",
"payload": { "cwd": "/my/project" }
}"#;
let sanitized = Sanitizer::sanitize(raw).expect("sanitization failed");
let obs = NewObservation {
kind: ObservationKind::SessionStart,
body: sanitized.body,
// … other fields …
};
store.writer.submit_observation(obs).await?;
ai‑memory‑llm: Provider‑Agnostic LLM and Embedding Traits
The ai‑memory‑llm crate abstracts over language model providers. It defines traits for chat completion (LlmProvider) and text embedding (Embedder), plus authentication boundary types.
This crate enables the system to work with multiple LLM backends without hardcoding provider‑specific logic throughout the codebase.
use ai_memory_llm::{LlmProvider, ProviderConfig};
let cfg = ProviderConfig::from_env().expect("missing LLM config");
let provider = LlmProvider::new(cfg);
let response = provider.chat("Summarize the recent session").await?;
ai‑memory‑consolidate: Auto‑Improvement Pipeline
The ai‑memory‑consolidate crate implements the background memory maintenance pipeline. It handles ingestion, linting, sweeping, and LLM‑driven page rewriting to improve memory quality over time.
Entry points include memory_consolidate for the full pipeline and auto_improve structs for configurable consolidation runs.
ai‑memory‑workstream: Native Transcript Handling
The ai‑memory‑workstream crate manages read‑only access to native transcripts and provides launch adapters for the managed workstream loop. This enables the ai‑memory run command to integrate with external coding sessions.
Key types include WorkstreamSelection and ManagedRunContext.
use ai_memory_workstream::run;
run()
.await
.expect("workstream run failed");
ai‑memory‑cli: Binary Entry Point and HTTP Glue
The ai‑memory‑cli crate provides the ai‑memory binary and thin HTTP subcommands that orchestrate the other crates. It contains the main entry point at [src/main.rs](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/main.rs).
Available subcommands include:
init— initialize a new data directoryrun— start the managed workstream loopbackup— create database archivesserve— run the HTTP server
# Initialise a new data directory
ai-memory init --data-dir /tmp/ai-memory-data
# Show recent pages
ai-memory read-page --path notes/todo.md
# Backup the database
ai-memory backup --to backup.tar.gz
Crate Dependency Patterns and Architectural Constraints
The ai‑memory crate architecture enforces several cross‑cutting invariants:
- Single‑writer SQLite: Only
ai‑memory‑storeopens write connections - Markdown source‑of‑truth: Only
ai‑memory‑wikimodifies markdown files - Explicit provider auth: LLM credentials never leak outside
ai‑memory‑llm - No internal reach: Crates use public APIs exclusively
These constraints prevent the tight coupling that typically degrades long‑term maintainability in multi‑crate Rust projects.
Summary
- ai‑memory‑core — domain types and identifiers with zero I/O
- ai‑memory‑store — exclusive SQLite access with single‑writer actor pattern
- ai‑memory‑wiki — atomic markdown operations and Git integration
- ai‑memory‑mcp — MCP tool exposure for external AI agents
- ai‑memory‑hooks — event sanitization for incoming webhooks
- ai‑memory‑llm — provider‑agnostic chat and embedding abstractions
- ai‑memory‑consolidate — background memory improvement pipeline
- ai‑memory‑workstream — transcript handling for managed sessions
- ai‑memory‑cli — binary entry point and command orchestration
Each crate's public API is defined in its respective src/lib.rs file under the crates/ directory, with implementation details hidden behind typed interfaces.
Frequently Asked Questions
What is the purpose of splitting ai‑memory into multiple crates?
The workspace structure enforces architectural boundaries at the compiler level. By isolating SQLite access to ai‑memory‑store and markdown handling to ai‑memory‑wiki, the codebase prevents accidental coupling and maintains clear data flow invariants documented in ARCHITECTURE.md.
Which ai‑memory crate should I import for custom integrations?
Import ai‑memory-mcp for adding memory capabilities to external tools via the Model Context Protocol. For direct database access, use ai‑memory-store with Store::open. The ai‑memory-core crate provides shared types when you need domain primitives without storage dependencies.
How does ai‑memory‑store handle concurrent access?
ai‑memory‑store implements a single‑writer actor pattern: one dedicated task owns the SQLite write connection, while ReaderPool manages multiple read‑only connections. This eliminates write contention without sacrificing read parallelism, as enforced by the crate's private constructor for WriterHandle.
Can I use ai‑memory‑llm with providers other than OpenAI?
Yes—ai‑memory‑llm defines provider‑agnostic traits (LlmProvider, Embedder) and uses ProviderConfig for authentication boundaries. The trait design allows adding new backends without modifying downstream crates that depend on LLM capabilities.
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 →