How the ai-memory Decay and Sweep Mechanism Works for Automatic Memory Pruning
The ai-memory decay and sweep mechanism calculates retention scores using exponential time decay and access frequency, then soft-deletes cold pages below a configurable threshold before permanently removing them after a grace period.
The akitaonrails/ai-memory repository implements an automatic memory pruning system that prevents unbounded SQLite storage growth. This decay and sweep mechanism evaluates page metadata to determine which observations and hand-offs have become stale, removing them through a two-phase deletion process that balances storage reclamation with operational safety.
How Retention Scoring Works
The Decay Formula
The core algorithm lives in crates/ai-memory-store/src/decay.rs. The retention_score function combines time-decay with access-boost terms to determine whether a page remains valuable.
The formula applies two exponential decay factors:
- Age decay:
exp(-λ·age)where λ (lambda) controls how quickly old pages lose value - Access decay:
σ·log(1+access_count)·exp(-μ·days_since_access)where σ (sigma) weights access frequency and μ (mu) decays the boost over time
The DecayParams struct encapsulates these coefficients along with cold_threshold (the score below which pages become deletion candidates).
Optional Breadth Weighting
For multi-actor scenarios, the retention_score_with_breadth function adds a breadth_weight parameter. This adjusts scores based on the number of distinct actors who have accessed the page, preventing premature deletion of widely-shared knowledge.
Candidate Selection and Sweep Actions
Scanning for Decay Candidates
The Reader struct in crates/ai-memory-store/src/reader.rs identifies targets through two query methods:
decay_candidates(lines ~2962–2986): Returns pages whereretention_score < cold_thresholdandpinned = falsedecay_tombstones_before(lines ~2997–3006): Returns already-soft-deleted rows older thanhard_delete_after_days
Both queries exclude pinned pages (where pinned = true), ensuring critical data survives sweeps regardless of score.
Soft-Delete and Tombstone Creation
When a candidate is identified, the system calls soft_delete_for_decay_if_latest in crates/ai-memory-store/src/ops.rs (lines ~1729–1760). This operation:
- Verifies the page is the latest version in its chain
- Sets
supersedes = NULLandsuperseded_at = now()to create a tombstone - Preserves the data for the grace period defined by
hard_delete_after_days
Soft-deleted pages remain readable but are excluded from future candidate scans, preventing redundant processing.
Hard-Delete with Recursive Chain Removal
After the grace period expires, hard_delete_decayed_page_chain (lines ~1883–1912 in ops.rs) executes a recursive CTE that walks the ancestry chain (decay_chain) and deletes every row in a single transaction. This SQLite-level recursion guarantees linear-time execution regardless of chain depth.
The Background Sweep Scheduler
The ai-memory-mcp server coordinates automatic pruning via Server::run_forget_sweep (around line 2125 in crates/ai-memory-mcp/src/server.rs). This background task:
- Runs every
interval_seconds(default 600 seconds) - Loads current
DecayParamsfromconfig.tomlon each iteration - Pulls candidates and tombstones via the
Reader - Executes soft-deletes for candidates
- Executes hard-deletes for expired tombstones
Because the scheduler reads configuration fresh on every cycle, parameter changes take effect immediately without server restart.
Configuration and Tuning
Configure the mechanism via the [decay] section in config.toml:
[decay]
lambda = 0.02 # per‑day exponential decay of age
sigma = 0.6 # strength of access‑boost
mu = 0.04 # decay of the access‑boost term
salience_default = 1.0
cold_threshold = 0.20 # below this → candidate
hard_delete_after_days = 180
breadth_weight = 0.0 # optional per‑actor weighting
interval_seconds = 600 # how often the sweep runs
Adjust cold_threshold to make the system more or less aggressive, or modify hard_delete_after_days to extend the recovery window for soft-deleted pages.
Code Examples
Programmatically evaluate retention scores using the decay module:
use ai_memory_store::{decay::{DecayParams, retention_score}, Store};
#[tokio::main]
async fn main() {
let store = Store::open("./ai_memory.db").await.unwrap();
// Retrieve page metadata
let page = store.reader.get_page("notes/todo.md").await.unwrap();
let age_days = page.age_days();
let access_cnt = page.access_count;
let days_since_access = page.days_since_last_access();
// Calculate retention score
let params = DecayParams::default();
let score = retention_score(
¶ms,
age_days,
access_cnt,
days_since_access,
page.salience,
);
if score < params.cold_threshold {
store.writer.soft_delete_for_decay_if_latest(&page.id).await.unwrap();
}
}
Manually trigger the sweep process for testing:
# Start the server with automatic sweeping
ai-memory --config ./config.toml
# Or invoke manually
ai-memory-mcp sweep-decay
Summary
- Exponential decay formula: Combines age decay and access frequency in
crates/ai-memory-store/src/decay.rs - Two-phase deletion: Soft-delete creates tombstones with a grace period; hard-delete uses recursive SQL for permanent removal
- Pinned protection: Setting
pinned = trueexempts pages from all candidate scans - Configurable thresholds:
cold_thresholdandhard_delete_after_dayscontrol aggressiveness and safety windows - SQLite-backed recursion: The
hard_delete_decayed_page_chainfunction leverages recursive CTEs for efficient chain deletion
Frequently Asked Questions
What happens to pinned pages during a sweep?
Pinned pages are excluded from both decay_candidates and decay_tombstones_before queries. When pinned = true, the page bypasses scoring entirely and survives regardless of age or access patterns. You must manually unpin a page before it becomes eligible for decay.
How is the retention score calculated?
The score combines exp(-λ·age) with σ·log(1+access_count)·exp(-μ·days_since_access). The retention_score function in crates/ai-memory-store/src/decay.rs multiplies these terms by the page's salience value. Higher access counts boost the score, but this boost decays exponentially based on days since last access.
Can I recover a page after it has been soft-deleted?
Yes. Soft-deletion creates a tombstone row that persists for hard_delete_after_days (default 180 days). During this grace period, operators can restore the page using an admin "undelete" command that clears the tombstone flags. Once hard-deletion runs, the page and its entire ancestry chain are permanently removed via recursive SQL deletion.
How often does the sweep run?
The background task runs every interval_seconds as defined in config.toml (default 600 seconds/10 minutes). The scheduler reads fresh DecayParams on each iteration, so configuration changes apply immediately to the next sweep cycle without requiring server restart.
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 →