How Versioned Wiki Pages Are Managed in ai-memory: A Deep Dive
ai-memory uses an immutable versioning strategy that combines SQLite rows with git-tracked files, where each write creates a new version while preserving full history through atomic database operations and automatic git commits.
Versioned wiki pages in ai-memory form the backbone of its knowledge management system. The akitaonrails/ai-memory repository implements a hybrid storage approach that treats the wiki as the single source of truth, ensuring no data loss while maintaining both programmatic queryability and human-readable file history.
Architecture Overview: The Three-Layer Storage Model
The versioning system spans three interconnected layers:
- SQLite store — Tracks version metadata with
is_latestflags - Filesystem — Holds markdown files at
<data_dir>/wiki/<workspace_id>/<project_id>/<page-path> - Git repository — Records every write as a commit for external tooling
This design, found in crates/ai-memory-wiki/src/wiki.rs lines 71–85 and 1629, guarantees durability and auditability without sacrificing query performance.
How New Versions Are Created
The Atomic Upsert Flow
When Wiki::write_page receives a NewPage command via WriterHandle::UpsertPage, it executes four atomic steps:
- Insert new row — Creates a version record with
is_latest = 1 - Invalidate previous version — Updates the prior row to
is_latest = 0 - Write filesystem — Persists markdown to the wiki directory
- Commit to git — Records the change through
GitAdapter
This sequence in crates/ai-memory-wiki/src/wiki.rs ensures that partial failures cannot leave the system in an inconsistent state. Either all four steps complete, or none do.
Database Schema Design
The pages table uses a soft-delete pattern rather than hard deletion or update-in-place:
// Conceptual schema (from ops.rs UpsertPage implementation)
// Row structure: id, workspace_id, project_id, path, title,
// frontmatter, body, created_at, is_latest
Only one row per unique (workspace_id, project_id, path) combination carries is_latest = 1. Historical versions remain queryable with is_latest = 0, enabling time-travel reads without separate history tables.
Code Example: Writing a Versioned Page
use ai_memory_wiki::{Wiki, NewPage, WriteContext};
use ai_memory_core::PagePath;
// Initialize wiki with git-backed storage
let wiki = Wiki::new(&data_dir, writer_handle.clone())?;
// This triggers the full versioning pipeline
wiki.write_page(
NewPage {
workspace_id: 1,
project_id: 42,
path: "architecture/decisions.md".into(),
title: Some("API Gateway Decision".into()),
frontmatter: serde_yaml::to_string(&meta)?,
body: "## Context\nWe chose Kong over NGINX...".into(),
},
&WriteContext::default(),
)?;
After execution, the filesystem contains <data_dir>/wiki/1/42/architecture/decisions.md with a corresponding git commit, and the database holds both the new version (is_latest = 1) and any prior versions (is_latest = 0).
Reading Versioned Content
Latest Version Retrieval
ReaderPool::read_page_latest in crates/ai-memory-store/src/reader.rs (lines 639–648) provides optimized access:
use ai_memory_wiki::PagePath;
// Single query: SELECT ... WHERE is_latest = 1
let current = wiki.read_page(&PagePath::new("architecture/decisions.md"))?;
println!("Version {}: {}", current.version_id, current.title);
Full Version History
For audit trails or rollback scenarios, read_page_versions exposes the complete chain without spawning new versions:
let history = wiki.read_page_versions(&PagePath::new("architecture/decisions.md"))?;
for version in history {
println!(
"v{} (latest={}) created at {}",
version.id, version.is_latest, version.created_at
);
}
This functionality, anchored in crates/ai-memory-store/src/reader.rs lines 760–770, powers re-indexing operations and historical analysis tools.
Git Integration for External Tooling
The GitAdapter in crates/ai-memory-wiki/src/git.rs bridges programmatic and human workflows. Every write_page generates:
- A git add of the modified markdown file
- A commit with metadata-derived message
- Optional push to remote (configurable)
This enables standard git tools—git log, git diff, GitHub interfaces—to inspect wiki history without database access.
Key Source Files Reference
| File | Lines | Purpose |
|---|---|---|
crates/ai-memory-wiki/src/wiki.rs |
71–85, 1629 | Core Wiki struct, write_page implementation, versioning logic |
crates/ai-memory-store/src/ops.rs |
— | UpsertPage command, atomic flag transitions |
crates/ai-memory-store/src/reader.rs |
639–648, 760–770 | Latest version queries, full history enumeration |
crates/ai-memory-wiki/src/git.rs |
— | Git repository operations, commit generation |
docs/wiki-migrations.md |
— | Schema evolution documentation |
Summary
- Immutable versions — Every write creates a new row; updates only toggle
is_latestflags - Atomic operations — Database and filesystem changes complete together or roll back
- Dual query paths — Fast latest-version lookups via
is_latest = 1index; full history via unfiltered queries - Git durability — Automatic commits provide human-readable history and external tool compatibility
- No data loss — Superseded versions remain accessible for audit and recovery
Frequently Asked Questions
How does ai-memory prevent version conflicts during concurrent writes?
The WriterHandle serializes all UpsertPage commands through a single writer thread, eliminating race conditions. SQLite's transaction isolation ensures that is_latest flag updates are atomic even under concurrent read pressure.
Can I restore a previous version of a wiki page?
Yes. Query the target version using read_page_versions, then call write_page with the historical content. This creates a new version with the restored content rather than mutating history, preserving the audit trail.
What happens to git history when pages are deleted?
Deletion sets is_latest = 0 for all versions of a page and removes the filesystem entry, but git retains the complete commit history. The database rows remain queryable through history APIs unless explicitly purged through separate maintenance operations.
Does versioning impact query performance?
No. The is_latest column is indexed, making latest-version queries O(1). Historical queries scan only rows for the specific page path, not the full table, as enforced by composite indexes on (workspace_id, project_id, path).
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 →