How the Decay Math Formula and Retention Scoring Work in ai-memory

The decay math formula combines exponential time decay with logarithmic access reinforcement to calculate retention scores that determine which episodic pages get evicted from ai-memory.

The akitaonrails/ai-memory repository implements a mathematically-grounded retention model to manage the lifecycle of episodic memory pages. At the heart of this system lies the decay math formula defined in crates/ai-memory-store/src/decay.rs, which computes retention scores by weighing page age against access patterns, user feedback, and optional actor breadth metrics.

Core Decay Parameters

The DecayParams struct in crates/ai-memory-store/src/decay.rs defines the tunable constants that govern the retention curve. These parameters allow operators to adjust the memory system's forgetfulness without altering the underlying code.

Parameter Default Mathematical Role
lambda 0.02 Controls exponential decay on age since updated_at (approximately 35-day half-life)
sigma 0.6 Sets the magnitude of the access-reinforcement boost
mu 0.04 Governs exponential decay on days since last access (recent hits matter more)
salience_default 1.0 Baseline salience for pages without explicit feedback
cold_threshold 0.20 Score floor below which pages become eviction candidates
hard_delete_after_days 180 Tombstone survival period before permanent removal

Source: DecayParams definition

The Retention Score Formula

The public API entry point retention_score delegates to retention_score_with_breadth with a breadth weight of zero, preserving backwards compatibility with the original historic formula.

pub fn retention_score(
    params: &DecayParams,
    age_days: f64,
    access_count: u32,
    days_since_access: Option<f64>,
    salience: Option<f64>,
) -> f64 {
    retention_score_with_breadth(
        params,
        age_days,
        access_count,
        days_since_access,
        salience,
        0,
        0.0,
    )
}

Source: retention_score implementation

Mathematical Components

The retention score calculation combines three distinct mathematical components:

Time Decay Term


salience * exp(-λ * age_days)

Older pages decay exponentially based on the lambda parameter, while higher salience values lift the entire curve upward.

Access Reinforcement Term


σ * ln(1 + access_count) * exp(-μ * days_since_access) * breadth

This term applies a logarithmic scaling to access frequency (ln(1 + access_count)) multiplied by its own exponential decay based on recency. The sigma parameter scales the boost magnitude.

Breadth Multiplier (Optional)


1 + breadth_weight * ln(1 + distinct_actors - 1)

When breadth_weight is non-zero, the formula accounts for social reinforcement by scaling the access term based on the count of distinct actors who accessed the page. With breadth_weight = 0, this term collapses to 1.

Source: retention_score_with_breadth core math

Salience Adjustments via Feedback

User feedback directly manipulates the salience variable before the retention calculation. The salience_after_feedback function in crates/ai-memory-store/src/decay.rs clamps adjustments within bounded limits to prevent single actors from permanently locking or instantly destroying pages.

pub fn salience_after_feedback(
    params: &DecayParams,
    current: Option<f64>,
    kind: ai_memory_core::FeedbackKind,
) -> f64 {
    let current = current.unwrap_or(params.salience_default);
    let next = match kind {
        K::Helpful => current + SALIENCE_STEP,
        K::NotHelpful => current - SALIENCE_STEP,
        K::Stale | K::Wrong => SALIENCE_MIN,
    };
    next.clamp(SALIENCE_MIN, SALIENCE_MAX)
}

Source: salience_after_feedback

  • Helpful feedback increases salience by SALIENCE_STEP (0.25), capped at SALIENCE_MAX (2.0)
  • NotHelpful decreases salience by 0.25, with a floor of SALIENCE_MIN (0.25)
  • Stale or Wrong feedback immediately floors salience to 0.25

These bounds ensure that the periodic retention sweep—not instantaneous feedback—governs long-term page eviction.

The Eviction Decision Flow

During the periodic forget sweep (ai_memory_store::Reader::decay_candidates), the system evaluates each page using the decay math formula:

  1. Calculate raw retention score using current metadata
  2. Compare against cold_threshold (default 0.20)
  3. Check PageMetadata::pinned status (pinned pages survive regardless of score)
  4. Candidates below threshold enter soft-delete → tombstone → hard-delete pipeline after hard_delete_after_days

Sources:

Practical Implementation Examples

Computing a Basic Retention Score

use ai_memory_store::decay::{DecayParams, retention_score};

fn main() {
    let params = DecayParams::default();
    let age_days = 45.0;
    let access_count = 12;
    let days_since_access = Some(3.0);
    let salience = None;  // uses salience_default (1.0)

    let score = retention_score(
        &params,
        age_days,
        access_count,
        days_since_access,
        salience,
    );
    println!("Retention score = {:.4}", score);
}

Applying Feedback and Recomputing

use ai_memory_store::decay::{salience_after_feedback, retention_score};
use ai_memory_core::FeedbackKind;

fn main() {
    let params = DecayParams::default();
    
    // User marks page as Helpful
    let new_salience = salience_after_feedback(
        &params,
        None,
        FeedbackKind::Helpful,
    );
    
    let score = retention_score(
        &params,
        10.0,           // age_days
        5,              // access_count
        Some(1.0),      // days_since_access
        Some(new_salience),
    );
    println!("Score after helpful feedback = {:.4}", score);
}

Incorporating Multi-Actor Breadth

use ai_memory_store::decay::{DecayParams, retention_score_with_breadth};

fn main() {
    let params = DecayParams::default();
    
    let score = retention_score_with_breadth(
        &params,
        30.0,           // age_days
        20,             // access_count
        Some(2.0),      // days_since_access
        None,           // default salience
        5,              // distinct_actors
        0.5,            // breadth_weight
    );
    println!("Score with actor breadth = {:.4}", score);
}

Summary

  • The decay math formula lives in crates/ai-memory-store/src/decay.rs and combines exponential time decay with logarithmic access reinforcement
  • Retention scoring weighs three factors: salience-adjusted age decay, recency-weighted access count, and optional social breadth
  • The cold_threshold parameter (default 0.20) determines eviction eligibility, while pinned pages bypass deletion regardless of score
  • User feedback adjusts salience within bounded limits (0.25 to 2.0) to prevent permanent locking or instant destruction of pages
  • Evicted pages enter a tombstone state for 180 days (hard_delete_after_days) before permanent removal

Frequently Asked Questions

What is the default half-life for page decay in ai-memory?

With the default lambda value of 0.02, pages experience approximately a 35-day half-life through pure time decay. This means a page with default salience (1.0) and no access reinforcement will see its time-decay component halve roughly every 35 days according to the exponential decay formula exp(-0.02 * age_days).

How does feedback affect the retention score calculation?

Feedback modifies the salience variable before the retention formula executes. Helpful feedback increments salience by 0.25 up to a maximum of 2.0, while NotHelpful decrements by 0.25 down to a minimum of 0.25. Stale or Wrong feedback immediately floors salience to 0.25. Because salience multiplies the time-decay term, higher values effectively raise the entire retention curve, extending page lifetime.

What happens when a page's retention score drops below the cold threshold?

When retention_score returns a value below cold_threshold (default 0.20) and the page is not pinned, it becomes a candidate for the forget sweep. The system initiates a soft-delete via soft_delete_for_decay_if_latest, creating a tombstone that persists for hard_delete_after_days (180 days by default) before hard deletion and permanent removal from the ancestry chain.

Can the decay parameters be tuned without modifying source code?

Yes, the DecayParams struct exposes all mathematical constants—including lambda, sigma, mu, and cold_threshold—as configuration parameters. According to the source in crates/ai-memory-mcp/src/server.rs, these values are exposed via the MCP admin API, allowing runtime adjustment of the retention model's sensitivity without recompiling the ai-memory store.

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 →