How ai-memory's Decay/Salience Model Works and What Memory Feedback Controls

ai-memory uses an exponential decay formula with tunable parameters to score page retention, where memory feedback directly adjusts salience to speed up or slow down memory loss.

The akitaonrails/ai-memory Rust crate implements a deterministic forgetting system for AI conversation memory. Every stored page receives a computed retention score that determines whether it survives periodic cleanup sweeps. The only way operators override automatic decay is through memory feedback — explicit signals like Helpful, NotHelpful, Stale, or Wrong that nudge a page's salience multiplier.

Decay/Salience Model: How Retention Scores Are Calculated

The core algorithm lives in crates/ai-memory-store/src/decay.rs. The retention_score function combines time decay, access patterns, and explicit salience into a single scalar:

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

The DecayParams Tunables

The model behavior is controlled through DecayParams, defined in the same file and exposed to users via TOML configuration:

Parameter Controls
lambda Per-day exponential decay on age_days (time since last content update)
sigma Magnitude of the access-reinforcement boost
mu Decay rate for access recency — recent hits matter more
salience_default Fallback salience when no explicit feedback exists
cold_threshold Score floor below which pages become eviction candidates
hard_delete_after_days Tombstone lifetime before permanent removal

The Retention Score Formula

The implementation breaks the score into two multiplicative terms:

  1. Time term: salience * exp(-lambda * age_days) — base decay modified by salience
  2. Access term: sigma * ln(1 + access_count) * exp(-mu * days_since_access) — logarithmic growth with count, penalized by staleness

A retention_score_with_breadth variant also accepts distinct_actors and breadth_weight to reward collaboratively-accessed pages.

Breadth-Aware Scoring

For team or multi-agent deployments, breadth weighting prevents single-user spam from artificially inflating scores. The distinct_actors count captures how many unique operators touched the page.

What Memory Feedback Tunes

Memory feedback is the operator override mechanism for automatic decay. When a retrieved page is marked with feedback, salience_after_feedback in decay.rs recomputes the salience multiplier:

pub fn salience_after_feedback(
    params: &DecayParams,
    current: Option<f64>,
    kind: ai_memory_core::FeedbackKind,
) -> f64

FeedbackKind Variants and Effects

Source: crates/ai-memory-core/src/page.rs

Feedback Salience Change Behavioral Effect
Helpful + SALIENCE_STEP Slows decay, extends retention
NotHelpful - SALIENCE_STEP Accelerates decay
Stale Reset to SALIENCE_MIN (0.25) Near-immediate eviction candidacy
Wrong Reset to SALIENCE_MIN (0.25) Same as Stale, routes to memory_lint report

Salience clamps between SALIENCE_MIN (0.25) and SALIENCE_MAX (2.0). Since the retention score multiplies the time term by salience, feedback creates multiplicative leverage on decay curves.

Feedback Does Not Delete Directly

Per crates/ai-memory-store/src/ops.rs, Stal and Wrong feedback only:

  • Reset salience to minimum
  • Generate lint entries for operator review

Actual deletion requires the periodic sweep to compute a sub-threshold retention score and invoke soft_delete_for_decay_if_latest.

Practical Code Examples

Computing Retention Manually

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

let params = DecayParams::default(); // λ=0.02, σ=0.6, μ=0.04, etc.
let age_days = 120.0;                // 4 months since update
let access_cnt = 30;
let days_since_access = Some(3.0);   // actively used 3 days ago
let salience = Some(1.5);            // previously rated Helpful

let score = decay::retention_score(
    &params, age_days, access_cnt, days_since_access, salience
);
// Score determines eviction candidacy vs. cold_threshold

Applying Feedback to Adjust Salience

use ai_memory_core::FeedbackKind;
use ai_memory_store::decay::{self, DecayParams};

let params = DecayParams::default();
let current = Some(1.0);
let new_salience = decay::salience_after_feedback(
    &params, current, FeedbackKind::Helpful
);
// new_salience = 1.0 + 0.25 = 1.25 (clamped if exceeding SALIENCE_MAX)

Store-Level Workflow

// Simplified from crates/ai-memory-store/src/ops.rs patterns
let feedback = FeedbackKind::NotHelpful;
let updated = decay::salience_after_feedback(
    &store.decay_params(),
    page.salience,
    feedback
);
store.update_page_salience(page.id, updated);
// Next sweep recomputes retention with new salience

Key Source Files Reference

File Responsibility
crates/ai-memory-store/src/decay.rs DecayParams, retention_score, salience_after_feedback, constants
crates/ai-memory-core/src/page.rs FeedbackKind enum, routing to lint reports
crates/ai-memory-store/src/ops.rs Store operations: feedback application, soft deletion logic
crates/ai-memory-mcp/src/server.rs TOML configuration exposure for decay parameters

Summary

  • Decay/salience model combines exponential time decay with logarithmic access reinforcement, tunable via six DecayParams.
  • Retention score is deterministic and recomputed per sweep; pages below cold_threshold become eviction candidates.
  • Memory feedback is the sole operator control mechanism, adjusting salience multipliers to accelerate (NotHelpful), slow (Helpful), or reset (Stale/Wrong) decay.
  • Feedback never deletes immediately — it nudges the curve and optionally routes to memory_lint for human review.
  • Salience bounds (0.25–2.0) create bounded but meaningful leverage over retention duration.

Frequently Asked Questions

What happens if I never provide memory feedback?

Pages use salience_default (typically 1.0) and rely purely on access patterns and age decay. Highly-accessed content survives longer; neglected content expires automatically.

How quickly does NotHelpful feedback erase a page?

It depends on current salience and other parameters. Each NotHelpful reduces salience by SALIENCE_STEP (0.25). At default settings, two consecutive negative ratings drop salience from 1.0 to 0.5, halving the time term's contribution and likely pushing the page below cold_threshold within the next sweep cycle.

Why don't Stale and Wrong delete immediately?

The design preserves auditability. These signals reset salience and flag pages in memory_lint, allowing operators to review what the system considered worth forgetting. Permanent deletion only occurs after hard_delete_after_days of tombstone status.

Can I disable decay entirely?

Not directly. You could set lambda = 0.0, mu = 0.0, and cold_threshold = -inf, but this is not the intended use case. The model assumes bounded memory requires bounded retention; feedback exists precisely to let operators influence what stays relevant.

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 →