How ai-memory Provides Persistent Cross-Session Memory for AI Coding Agents

ai-memory enables persistent, cross-session memory by treating a directory-local markdown wiki as the single source of truth and building a derived SQLite index that agents query at runtime.

AI coding agents traditionally lose all context when a terminal session ends. The akitaonrails/ai-memory project solves this with a Git-backed wiki architecture where every observation gets written atomically to markdown and indexed for fast retrieval. This article explains the seven-stage workflow—from lifecycle hooks to retention policies—that makes cross-session memory possible.

The Core Architecture: Wiki-First, Index-Second

Unlike systems that store everything in an opaque database, ai-memory uses a human-readable markdown wiki as the authoritative source. The SQLite database exists only as a performance-optimized derivative.

This design delivers three advantages for AI coding agents:

  • Durability – The wiki is a standard Git repository with full version history
  • Portability – Any tool can read the markdown without special drivers
  • Inspectability – Developers can browse, search, and edit memory with standard tools

The trade-off is a single-writer bottleneck that serializes all mutations through a dedicated actor.

Stage 1: Lifecycle Hook Emission

Every agent action triggers a JSON hook to the /hook endpoint. In crates/ai-memory-hooks/src/lib.rs, the router sanitizes payloads and assigns an ObservationKind:

Kind Trigger
session-start New CLI invocation or IDE window opened
user-prompt Agent receives a coding request
tool-execution Agent runs a command or edits a file
session-end Process termination or explicit cleanup

Each observation becomes a WriteCmd enqueued to the single-writer SQLite actor defined in crates/ai-memory-store/src/writer.rs.


# Example: Start a managed workstream that emits session-start

ai-memory run

Stage 2: Atomic Markdown Persistence

The writer actor persists observations by appending to markdown pages under <data_dir>/wiki/. In crates/ai-memory-wiki/src/atomic.rs, writes use a temp-file + rename + fsync sequence that guarantees atomicity even on power loss:

// From ai-memory-wiki/src/atomic.rs
pub fn atomic_write(path: &Path, content: &[u8]) -> io::Result<()> {
    let temp = NamedTempFile::new_in(path.parent().unwrap())?;
    temp.as_file().write_all(content)?;
    temp.as_file().sync_all()?;      // fsync before rename
    temp.persist(path)?;             // atomic rename
    Ok(())
}

This ensures the wiki never contains partially-written pages. Common page paths include:

  • log.md – Chronological event stream
  • notes/*.md – Developer-captured insights
  • sessions/<id>.md – Auto-generated session summaries

Stage 3: Derived SQLite Indexing

While the wiki remains the source of truth, crates/ai-memory-store/src/lib.rs maintains a derived database at <data_dir>/db/memory.sqlite with tables for:

  • pages – Markdown file metadata with access counters
  • observations – Individual hook payloads with timestamps
  • links – Cross-references between pages
  • page_embeddings – Optional vector representations for semantic search

The schema enables FTS5 full-text search and vector RRF retrieval when embeddings are configured. Updates happen synchronously with markdown writes to maintain consistency.

Stage 4: Session Synthesis and Handoffs

When a session-end hook arrives, the server performs two critical operations:

  1. Generate session summary – Creates sessions/<id>.md with condensed context
  2. Create handoff row – Inserts memory_handoff_begin pointing to the next expected agent

This memory handoff eliminates manual context copying. A developer running Claude Code at 9 AM can resume with Codex at 2 PM with zero friction.


# End session; creates summary and handoff automatically

ai-memory finalize-session

Stage 5: Runtime Query Surface

Agents retrieve memory through MCP tools implemented in crates/ai-memory-store/src/fts_query.rs. The three primary tools are:

  • memory_query – FTS5 + entity-match + optional vector RRF
  • memory_read_page – Direct markdown retrieval by path
  • memory_briefing – Aggregated context for session startup

Each query bumps pages.access_count, enabling the retention system to identify hot versus cold knowledge.


# Search across all remembered pages with relevance scoring

ai-memory query "how to configure auto-improve"

For programmatic access from custom agents:

use ai_memory_client::MemoryClient;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = MemoryClient::new("http://127.0.0.1:49374")?;
    
    let resp = client.memory_query()
        .query("embedding provider")
        .limit(5)
        .send()
        .await?;
        
    for hit in resp.hits {
        println!("▶ {} ({:.2})", hit.path, hit.score);
    }
    Ok(())
}

Stage 6: Optional LLM Consolidation

When AI_MEMORY_LLM_PROVIDER is set, the memory_consolidate tool in crates/ai-memory-consolidate/src/lib.rs rewrites episodic logs into semantic knowledge. This transforms raw event streams into organized documentation that survives long-term.

The consolidation pipeline:

  1. Identifies related observations and pages
  2. Generates LLM summaries with source attribution
  3. Proposes structural improvements (merging, splitting, linking)
  4. Applies changes atomically through the standard writer path

Without consolidation, memory remains searchable but fragmented. With it, the wiki becomes a curated knowledge base.

Stage 7: Retention and Decay

A periodic forget-sweep prevents unbounded growth:

  • Evicts pages below an access threshold
  • Respects explicit TTLs on observations
  • Purges tombstoned records after grace period
  • Preserves pinned knowledge regardless of temperature

This keeps query latency bounded while protecting critical context. The sweep runs as a background task in the writer actor, never blocking agent operations.

Key Source Files

Component Path Purpose
Hook router crates/ai-memory-hooks/src/lib.rs Validates JSON, assigns ObservationKind, enqueues writes
Wiki API crates/ai-memory-wiki/src/lib.rs High-level markdown page operations
Atomic writes crates/ai-memory-wiki/src/atomic.rs Crash-safe file persistence
Writer actor crates/ai-memory-store/src/writer.rs Serialized DB mutations and FTS5 updates
Query engine crates/ai-memory-store/src/fts_query.rs FTS5 + entity + vector RRF search
CLI entry crates/ai-memory-cli/src/main.rs Subcommand parsing and execution
Consolidation crates/ai-memory-consolidate/src/lib.rs LLM-driven page rewriting

Summary

  • Wiki-first design makes memory human-readable and Git-versioned
  • Atomic writes via temp-file + rename + fsync guarantee durability
  • Single-writer actor serializes mutations while allowing concurrent reads
  • Session handoffs enable seamless context transfer between agents and sessions
  • FTS5 + optional vector search delivers fast, relevant retrieval
  • LLM consolidation transforms raw logs into structured knowledge
  • Forget-sweep retention bounds storage without losing important context

Frequently Asked Questions

What makes ai-memory different from a simple log file?

Traditional logs are write-only streams that grow indefinitely. ai-memory maintains a bidirectional relationship between markdown content and a queryable SQLite index. Every write updates FTS5 and optional embedding tables, while every query feeds back into access statistics that drive retention. The atomic write protocol in crates/ai-memory-wiki/src/atomic.rs also ensures crash safety that append-only logs lack.

How does cross-session persistence actually work?

When an agent starts, it loads the memory_handoff_begin row created by the previous session's finalize-session command. This points to the summary page and relevant context pages. Because the wiki is directory-local and Git-backed, any subsequent agent invocation in the same repository sees identical state. No network sync or explicit export is required.

Can I use ai-memory without an LLM provider?

Yes. The core functionality—hook ingestion, atomic markdown writes, FTS5 search, and session handoffs—works entirely offline. LLM consolidation via memory_consolidate is optional and only activates when AI_MEMORY_LLM_PROVIDER is configured. Without it, you'll have searchable but unconsolidated episodic memory.

What happens if the SQLite database is corrupted?

The database is strictly a performance derivative. Delete <data_dir>/db/memory.sqlite and restart the server; it will rebuild the entire index from the markdown wiki in crates/ai-memory-store/src/lib.rs. This reconstruction preserves all content because the wiki is the authoritative source.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →