# How the Decay Policy Works for Different Memory Tiers in ai-memory

> Understand ai-memory's decay policy for tiered memory. Learn how working, episodic, and semantic memory retention scores ensure efficient data management.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: deep-dive
- Published: 2026-09-10

---

**The decay policy applies a four-tier retention strategy where working memory remains permanently pinned, episodic memory decays based on a mathematical retention score, and semantic/procedural memory persists long-term through elevated salience values.**

In the `akitaonrails/ai-memory` system, every unit of knowledge is stored as a **page** (a markdown file) assigned to one of four distinct tiers defined in the `Tier` enum. The **decay policy** governs how these pages age out of the system using the configurable `DecayParams` struct, allowing projects to balance storage constraints against knowledge retention requirements.

## The Four Memory Tiers

The `Tier` enum in [`crates/ai-memory-core/src/page.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-core/src/page.rs) (lines 22-30) categorizes knowledge into four groups, each with specific decay behaviors enforced by the retention engine.

### Working Memory

Working memory contains short-lived session data that must remain available for the active context. When the slot-page writer creates pages in this tier, it automatically sets `pinned = true`, causing the decay sweep to skip them entirely. As implemented in [`crates/ai-memory-wiki/src/wiki.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/wiki.rs) (lines 721-734), any page carrying the `pinned` flag is excluded from eviction regardless of its age or access patterns.

### Episodic Memory

Episodic memory stores per-session summaries and concepts and is **subject to active decay**. The periodic forget-sweep calls `Reader::decay_candidates` in [`crates/ai-memory-store/src/reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/reader.rs) (lines 3294-3318) to fetch all non-pinned pages. For each candidate, the system calculates a **retention score** using `retention_score` or `retention_score_with_breadth` from [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs) (lines 48-74). If the score falls below the `cold_threshold` (default 0.20), the page becomes an eviction candidate and may be soft-deleted via `Writer::soft_delete_for_decay_if_latest` in [`crates/ai-memory-store/src/writer.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/writer.rs) (lines 1432-1451).

### Semantic Memory

Semantic memory holds long-term factual and wiki pages that are **generally immune to decay**. While the sweep still evaluates these pages, they typically maintain scores above the `cold_threshold` due to higher default salience values or manual pinning. This design ensures critical reference material persists indefinitely while still allowing administrators to force removal when necessary.

### Procedural Memory

Procedural memory contains reusable patterns extracted from episodic clusters. The decay policy treats these pages identically to semantic memory, assigning higher base salience that resists standard retention decay. Like semantic pages, they rely on elevated initial salience or explicit pinning to remain above eviction thresholds.

## How the Retention Score Is Calculated

The `retention_score` function in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs) (lines 48-74) computes a floating-point value between 0.0 and 1.0 that determines whether a page survives the next sweep. The calculation combines three mathematical factors:

1. **Age decay**: `salience * exp(-λ * age_days)` — The base salience fades exponentially over time using the decay constant λ (lambda).
2. **Access reinforcement**: `σ * log(1 + access_count) * exp(-μ * days_since_access)` — Recent access patterns boost retention, but this bonus itself decays based on the access decay constant μ (mu).
3. **Breadth weighting**: When `breadth_weight` > 0, the `retention_score_with_breadth` function (lines 77-102) adds a bonus proportional to `distinct_actors`, rewarding pages accessed by many different operators.

The parameters λ (lambda), σ (sigma), μ (mu), and default salience values are configurable per project via the `[decay]` section in [`config.toml`](https://github.com/akitaonrails/ai-memory/blob/main/config.toml) and injected through `Builder::with_decay_params` in [`crates/ai-memory-mcp/src/server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/server.rs) (lines 382-388).

## The Decay Sweep Process

The decay sweep operates as a background maintenance routine with three distinct phases:

1. **Candidate selection**: The `Reader::decay_candidates` method queries for all pages where `pinned` is false, returning the entire corpus of evictable knowledge.
2. **Score evaluation**: Each candidate's retention score is computed against the project's `DecayParams`. Pages scoring below `cold_threshold` (0.20) are marked as cold.
3. **Graduated deletion**: Cold pages are soft-deleted immediately via `soft_delete_for_decay_if_latest`. After `hard_delete_after_days` (default 180 days), these entries are permanently purged from storage.

## Pinning and Configuration

You can override the tier-based decay logic for any individual page by setting `pinned: true` in the page metadata. This flag takes precedence over all scoring calculations, making it useful for preserving critical episodic data that would otherwise age out.

```rust
use ai_memory_store::decay::{DecayParams, retention_score};
use ai_memory_core::page::Tier;

// Initialize default decay parameters
let params = DecayParams::default(); // lambda=0.02, sigma=0.6, cold_threshold=0.20

// Calculate retention for a 6-month-old episodic page with 12 accesses
let score = retention_score(&params, 180.0, 12, Some(2.0), None);

if score < params.cold_threshold {
    println!("Page qualifies for decay");
}

```

To pin a page permanently:

```rust
let new_page = NewPage {
    workspace_id,
    project_id,
    path,
    title,
    body,
    tier: Tier::Episodic,
    pinned: true, // Decay sweep will ignore this page
    ..Default::default()
};
wiki.write_page(new_page).await?;

```

## Summary

- Working memory pages are automatically pinned and never decay.
- Episodic memory pages calculate retention scores based on age, access frequency, and breadth, expiring when scores drop below 0.20.
- Semantic and procedural memory tiers rely on high base salience to remain immune from standard decay sweeps.
- The `pinned` flag overrides all tier logic, granting permanent immunity to any page.
- Configuration occurs through `DecayParams` in [`config.toml`](https://github.com/akitaonrails/ai-memory/blob/main/config.toml), controlling lambda, sigma, mu, and deletion thresholds.

## Frequently Asked Questions

### How do I prevent specific episodic pages from decaying?

Set the `pinned` field to `true` when creating or updating the page. This flag causes the decay sweep to skip the page entirely, regardless of its tier or retention score, as implemented in the filter logic of [`crates/ai-memory-wiki/src/wiki.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/wiki.rs) (lines 721-734).

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

The page is marked as a decay candidate and soft-deleted via `Writer::soft_delete_for_decay_if_latest` in [`crates/ai-memory-store/src/writer.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/writer.rs) (lines 1432-1451). It remains recoverable until `hard_delete_after_days` (180 days by default) elapses, at which point it is permanently removed from the store.

### Can I adjust how aggressively episodic memory decays?

Yes. Modify the `lambda` (age decay rate), `sigma` (access weight), and `mu` (access decay rate) values in the `[decay]` section of your [`config.toml`](https://github.com/akitaonrails/ai-memory/blob/main/config.toml). These parameters are injected into the store via `Builder::with_decay_params` in [`crates/ai-memory-mcp/src/server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/server.rs) (lines 382-388) and directly influence the retention score calculation in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs).

### Why does working memory not use the retention scoring system?

Working memory is designed for ephemeral session data that should persist only for the active context. The slot-page writer automatically sets `pinned = true` for all working tier pages, effectively excluding them from the `decay_candidates` query and ensuring they remain available until explicitly removed or the session ends.