# How Pinned Pages Affect Retention in ai-memory: A Complete Technical Guide

> Discover how pinned pages in ai-memory ensure permanent data retention by bypassing the forget sweep. Learn the technical details for guaranteed data persistence in this complete guide.

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

---

**Pinned pages are completely immune to decay in ai-memory—the forget sweep explicitly excludes any row where `pinned = true`, guaranteeing permanent retention unless manually deleted.**

The ai-memory system implements a tiered memory architecture where most content ages out according to configurable decay rules. However, certain pages require indefinite persistence. This article examines exactly how the `pinned` flag operates within the decay subsystem, with direct reference to the implementation in `akitaonrails/ai-memory`.

## The Decay Subsystem and Pinned Exclusion

The retention mechanism centers on a periodic "forget sweep" that evaluates pages for eviction. The sweep queries decay candidates based on **tier** (typically `episodic`) and critically filters out pinned content.

In [`crates/ai-memory-store/src/reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/reader.rs), the decay candidate selection explicitly excludes pinned rows:

```rust
// sweep itself filters by tier (only `episodic`) + pinned flag,
// "SELECT … tier, pinned …"  (see line 3243)

```

This query construction ensures that `pinned = true` rows never enter the decay pipeline. The database column acts as a hard gate—no subsequent decay logic ever processes these pages.

## Automatic Pinning for Slot Pages

Pages written under the internal `_slots/` namespace receive automatic pinning. This design choice treats slot pages as system-critical infrastructure that must survive all retention policies.

The unit test `slot_pages_are_pinned_automatically` in [`crates/ai-memory-wiki/src/wiki.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/wiki.rs) validates this behavior:

```rust
assert!(candidates[0].pinned, "slot pages should be decay-immune");   // line 3318

```

Any path prefix-matched to `_slots/` triggers this automatic pinning at write time, without requiring explicit front-matter configuration.

## Manual Pinning via Front-Matter

Users can pin arbitrary pages by setting `pinned: true` in front-matter. The wiki writer extracts this value and persists it to the database.

In [`crates/ai-memory-wiki/src/wiki.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/wiki.rs) at line 560:

```rust
let pinned = meta.pinned;

```

The writer then propagates this boolean into the store's `pinned` column, making the page decay-immune immediately upon persistence.

## Practical Code Examples

### Pin a Page via Front-Matter

```rust
use ai_memory_wiki::Wiki;
use serde_json::json;

let path = "notes/important.md";
let body = "Critical design decisions.";
let meta = json!({
    "title": "Important Notes",
    "pinned": true          // <- retention-immune
});

let req = wiki::write_page_req(path, body, meta);
wiki.write_page(req).await.unwrap();

```

### Create an Auto-Pinned Slot Page

```rust
let slot_path = "_slots/project-context.md";
let body = "Current project context…";
wiki.write_page(wiki::write_page_req(slot_path, body, json!({})))
    .await
    .unwrap();   // pinned: true applied automatically

```

### Verify Decay Candidate Exclusion

```rust
let candidates = store.reader.decay_candidates(ws, proj).await.unwrap();
assert!(candidates.iter().all(|c| !c.pinned));   // pinned pages absent

```

## Key Implementation Files

| Component | File | Significance |
|-----------|------|------------|
| Wiki writer | [`crates/ai-memory-wiki/src/wiki.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-wiki/src/wiki.rs) | Extracts `meta.pinned` from front-matter (line 560); validates slot pinning (line 3318) |
| Decay candidate query | [`crates/ai-memory-store/src/reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/reader.rs) | Excludes pinned rows from sweep (lines 3243-3245) |
| Decay engine | [`crates/ai-memory-store/src/decay.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/decay.rs) | Applies aging formulas only to non-pinned pages |
| Slot write path | [`crates/ai-memory-store/src/writer.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/writer.rs) | Implicitly sets `pinned: true` for `_slots/` pages |

## Summary

- **Pinned pages are decay-immune**: The forget sweep filters `pinned = true` at the query level in [`reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/reader.rs)
- **Two pinning mechanisms**: Explicit front-matter flag or automatic `_slots/` namespace detection
- **Permanent retention**: Pinned pages persist until explicit deletion, regardless of access patterns or age
- **Validated by tests**: `slot_pages_are_pinned_automatically` guarantees the behavior

## Frequently Asked Questions

### Can a pinned page ever be deleted?

Yes. Pinning only prevents **automatic** decay eviction through the forget sweep. Explicit deletion operations—whether through API calls or direct database operations—still remove pinned pages. The immunity applies solely to the automated retention system.

### What happens if I unpin a previously pinned page?

Removing `pinned: true` from front-matter and rewriting the page clears the database flag. On subsequent decay sweeps, the page becomes eligible for evaluation based on its tier, age, and access patterns. There is no retroactive decay—eligibility begins from the unpinning moment.

### Are there performance implications for pinning many pages?

The decay candidate query in [`reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/reader.rs) must scan and filter all rows in the tier, including pinned ones. While the `pinned` column likely has an index, extremely large pinned populations could increase query overhead. However, since pinned pages never enter the expensive decay calculation pipeline, the overall cost is typically lower than managing equivalent unpinned content.

### Why does the `_slots/` namespace receive automatic pinning?

Slots serve as structured, system-addressable memory locations—often containing active context, tool configurations, or session state. Automatic pinning ensures these operational pages survive across decay cycles without requiring manual front-matter maintenance, reducing the risk of accidental context loss during long-running sessions.