# How to Configure Memory Decay and Retention Policies in ai-memory

> Learn to configure memory decay and retention policies in ai-memory using the .ai-memory.toml file. Control salience reduction and set fine-grained TTL overrides.

- Repository: [Fabio Akita/ai-memory](https://github.com/akitaonrails/ai-memory)
- Tags: how-to-guide
- Published: 2026-09-06

---

**ai-memory uses a configurable decay engine that applies exponential salience reduction to episodic pages, controlled through a `[decay]` table in [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) with optional pinning and TTL overrides for fine-grained retention control.**

Memory decay and retention policies in the `akitaonrails/ai-memory` repository keep your knowledge base fresh while preserving critical information. The system targets **episodic pages**—raw observations generated by agents—and applies configurable aging algorithms that you can tune per project or override per page.

## The Decay Configuration File

All decay settings live in a project-level [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) file. The server reads this configuration once at startup via `Config::load()` in [`crates/ai-memory-mcp/src/server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/server.rs) (lines 298–385).

### Core Decay Parameters

The `[decay]` table supports these fields:

| Parameter | Default | Purpose |
|-----------|---------|---------|
| `lambda` | 0.02 day⁻¹ | Per-day exponential decay rate for salience |
| `observation_retention_days` | 0 (disabled) | TTL for raw observation rows before hard deletion |
| `observation_prune_batch` | varies | Maximum rows removed per forget-sweep |
| `breadth_weight` | 0.0 | Bonus salience for pages with many inbound links |
| `inactivity_days` | 7 | Minimum idle time before a page becomes eligible for decay |

### Sample Configuration

```toml

# .ai-memory.toml

[decay]
lambda = 0.02
observation_retention_days = 30
observation_prune_batch = 500
breadth_weight = 0.1
inactivity_days = 7

```

The server injects these values into the `DecayParams` struct via `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 1777–1784).

## How the Decay Algorithm Works

The decay engine lives in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs). It computes **salience**—a score representing a page's relevance—and reduces it exponentially based on age.

### Exponential Salience Decay

The function `salience_after_feedback` applies the formula using your configured `lambda`:

```rust
// Conceptual implementation based on decay.rs
new_salience = current_salience * exp(-lambda * days_since_access)

```

A smaller `lambda` slows decay; larger values make pages become stale faster.

### The Forget-Sweep Process

The decay system runs periodically (default: hourly) and performs these operations:

1. **Candidate selection** — `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) enumerates pages eligible for decay, excluding pinned rows (checked in `row_to_decay_candidate`, lines 1116–1120)
2. **Salience recalculation** — Pages with updated salience below threshold become **decay tombstones**
3. **TTL enforcement** — Pages with expired `expires_at` timestamps are removed regardless of salience (handled in `soft_delete_for_decay_if_latest` in [`crates/ai-memory-store/src/ops.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/ops.rs), lines 2077–2081)
4. **Batch pruning** — Raw observations older than `observation_retention_days` are hard-deleted, capped by `observation_prune_batch`

## Retention Mechanisms Beyond Decay

### Pinning Pages for Permanent Retention

Pinned pages are immune to all decay calculations. Use this for architecture decisions, API contracts, or any knowledge that must persist indefinitely.

**CLI approach:**

```bash
ai-memory pin docs/important/architecture.md

```

Internally, this sets `pinned = true` on the pages row. The `decay_candidates` query automatically excludes these rows.

**Front-matter approach:**

```markdown
---
title: "Core System Architecture"
pinned: true
---

```

The pinning logic is implemented in [`crates/ai-memory-wiki/src/wiki.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/wiki.rs) (line 864).

### Per-Page TTL with expires_at

Override decay behavior for temporary content using a timestamp:

```markdown
---
title: "Sprint 47 Experiment Notes"
expires_at: "2027-01-01T00:00:00Z"
---

```

When the forget-sweep encounters this page after the timestamp, it removes the page immediately—salience scores are ignored.

### Breadth-Weighted Salience

The `breadth_weight` parameter rewards pages referenced from many contexts. If set to 0.1, a page with 10 unique inbound links receives a salience bonus proportional to that count. This preserves "hub" pages that serve as connection points in your knowledge graph.

## Runtime Configuration Updates

The MCP server exposes an admin endpoint to adjust decay without restarting:

```http
POST /admin/config
Content-Type: application/json

{
  "decay_params": {
    "lambda": 0.015,
    "observation_retention_days": 60,
    "observation_prune_batch": 1000,
    "breadth_weight": 0.2,
    "inactivity_days": 10
  }
}

```

The server merges this payload into its active `DecayParams` via `with_decay_params` in [`server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/server.rs).

## Tuning Strategies for Different Use Cases

**Aggressive pruning for high-volume agents:**

```toml
[decay]
lambda = 0.05
observation_retention_days = 7
observation_prune_batch = 2000

```

**Conservative retention for long-lived knowledge bases:**

```toml
[decay]
lambda = 0.005
breadth_weight = 0.15
inactivity_days = 30

```

**Hybrid: permanent core, decaying experiments:**
- Pin `docs/architecture/` and `docs/api/`
- Set `expires_at` on experiment notes
- Use default `lambda` for everything else

## Summary

- Configure decay parameters in [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) under the `[decay]` table; the server loads these at startup via `Config::load()` in [`crates/ai-memory-mcp/src/server.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-mcp/src/server.rs)
- The exponential decay algorithm in [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs) uses `lambda` to control salience reduction speed
- Pin critical pages via CLI (`ai-memory pin`) or `pinned: true` in front-matter to exclude them from all decay
- Set `expires_at` timestamps for temporary content that should disappear regardless of access patterns
- Adjust `breadth_weight` to preserve well-connected "hub" pages in your knowledge graph
- Use the `/admin/config` MCP endpoint to update parameters at runtime without restarting

## Frequently Asked Questions

### What happens if I don't create an [`.ai-memory.toml`](https://github.com/akitaonrails/ai-memory/blob/main/.ai-memory.toml) file?

The server uses default values: `lambda = 0.02`, `observation_retention_days = 0` (disabled), and `breadth_weight = 0.0`. Decay proceeds with these conservative defaults, but no raw observations are automatically pruned.

### Can I disable decay entirely?

Set `lambda = 0.0` and ensure no pages have `expires_at` timestamps. Alternatively, pin all pages you want to preserve—though this is impractical for large systems. There is no global "disable decay" flag; you must configure parameters to effectively neutralize it.

### What's the difference between a decay tombstone and hard deletion?

A **decay tombstone** marks a page as obsolete but preserves its history and relationships; it becomes invisible to normal queries but remains in storage. **Hard deletion** permanently removes data and occurs only for raw observations past their `observation_retention_days` TTL or pages with expired `expires_at` timestamps.