# What the ai-memory Curator Maintenance Command Detects and Reports: A Complete Guide

> Discover what the ai-memory curator maintenance command detects: cold pages, stale slots, duplicate titles, and dangling links. Get a complete health report for your project.

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

---

**The ai-memory curator is a read-only, rule-based maintenance tool that scans projects for four specific health signals—cold episodic pages, stale slots, duplicate titles, and dangling cross-project links—producing a markdown report without modifying any data.**

The `ai-memory curator` command helps operators maintain clean, well-organized knowledge bases by identifying conservative "health signals" that may require manual attention. Unlike destructive maintenance operations, the curator is explicitly designed as a **detection-only** tool—it never edits, deletes, merges, or rewrites content. This article explains exactly what the curator detects, how it identifies each issue, and how to interpret its reports based on the actual implementation in [akitaonrails/ai-memory](https://github.com/akitaonrails/ai-memory).

## Four Health Signals the Curator Detects

The curator implementation in [`crates/ai-memory-consolidate/src/curator.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-consolidate/src/curator.rs) scans for four distinct finding types. Each uses specific detection logic against the store and wiki.

### Cold Episodic Pages

The curator identifies **cold episodic** pages that the forget-sweep would evict due to low retention scores.

Detection works as follows:

1. Pages are filtered to `Tier::Episodic` tier only.
2. Each page is scored using `retention_score_with_breadth`.
3. If the score falls below `decay_params.cold_threshold`, a finding is generated.

The relevant code spans lines 30-46 in [`curator.rs`](https://github.com/akitaonrails/ai-memory/blob/main/curator.rs). **Pinned pages are excluded** from this check—either column-pinned pages or those with front-matter `pinned: true` are skipped via the `frontmatter_pinned` helper (lines 3-8).

Typical finding:

```

cold_episodic (info) — Episodic page sessions/old.md is cold (score 0.018, age 200 days)

```

### Stale Slot Pages

The curator detects **stale_slot** findings when pages under `_slots/` haven't been updated within configurable thresholds.

Detection logic (lines 78-86):
- [`_slots/current-focus.md`](https://github.com/akitaonrails/ai-memory/blob/main/_slots/current-focus.md): 7-day threshold (`current_focus_stale_days`)
- Other slots: 30-day threshold (`other_slot_stale_days`)

The slot's `updated_at` timestamp is parsed and compared against these thresholds. This helps ensure active project focus and slot currency.

### Duplicate Titles

The **duplicate_title** finding catches naming collisions that could confuse linking or navigation.

Detection (lines 100-118):
- Titles are normalized via `normalize_title` (whitespace collapsed, lower-cased)
- Normalized titles are tracked in a `HashMap<String, Vec<PathBuf>>`
- Any entry with multiple paths generates a finding

**Pages under `_pending/` are excluded** from this check to avoid false positives from draft content.

Example output:

```

duplicate_title (info) — 2 pages share the normalized title 'release notes'
  - Pages: decisions/release-b.md, notes/release-a.md

```

### Dangling Cross-Project Links

The curator identifies **dangling_cross_project_link** findings when wiki links reference non-existent pages in other projects.

Detection (lines 124-136):
- Uses the store's `dangling_cross_project_links` query
- Each finding includes the link target and a boolean indicating whether the target project exists

This prevents broken references and helps maintain wiki integrity across project boundaries.

## Running the Curator Command

The curator supports two primary modes: immediate report generation and staged reporting.

### Dry-Run Report (Default)

Print findings as JSON to stdout without creating any files:

```bash
ai-memory curator --project scratch

```

### Staged Reporting

Stage a report page for later human review and approval:

```bash
ai-memory curator --stage --project scratch

```

## Understanding Curator Output Format

The curator generates structured markdown reports with explicit safety warnings. A typical report includes:

```markdown

# Curator Report

> Report-only: approving this pending write stores this report page only.
> It does not edit, delete, merge, rewrite links, or update slots.

- Workspace: `default`
- Project: `scratch`
- Generated: `2026-08-30T12:34:56Z`
- Summary: 4 conservative curator finding(s).

## Findings

- **cold_episodic** (info) — Episodic page sessions/old.md is cold (score 0.018, age 200 days)
  - Pages: `sessions/old.md`

- **stale_slot** (warning) — Slot _slots/current-focus.md has not changed for 8 days (threshold 7)
  - Pages: `_slots/current-focus.md`

- **duplicate_title** (info) — 2 pages share the normalized title 'release notes'
  - Pages: `decisions/release-b.md`, `notes/release-a.md`

- **dangling_cross_project_link** (warning) — notes/links.md links to missing cross‑project target default/ghost-project/nope.md
  - Pages: `notes/links.md`

```

The `dry_run` flag in the report struct and explicit comments in `render_curator_report_markdown` (lines 64-68) reinforce that approval only stores the report page itself—no maintenance actions execute.

## Programmatic Access in Rust

Integrate curator scanning into custom tooling using the public API:

```rust
use ai_memory_consolidate::curator::{run_curator_report, CuratorParams};
use ai_memory_store::ReaderPool;

// Assume `reader`, `ws_id`, `proj_id` are already set up.
let params = CuratorParams::default();
let report = run_curator_report(
    &reader, 
    ws_id, 
    proj_id,
    "default", 
    "scratch", 
    params
).await?;

println!("Found {} findings", report.findings.len());

```

## Key Source Files

| File | Purpose |
|------|---------|
| [`crates/ai-memory-consolidate/src/curator.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-consolidate/src/curator.rs) | Core implementation: finding detection, scoring, and markdown rendering |
| [`crates/ai-memory-store/src/reader.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-store/src/reader.rs) | Store read APIs: `decay_candidates`, `list_pages`, `dangling_cross_project_links` |
| [`crates/ai-memory-cli/src/cli.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-cli/src/cli.rs) | CLI sub-command and flag definitions |
| [`docs/auto-improvement-loop.md`](https://github.com/akitaonrails/ai-memory/blob/main/docs/auto-improvement-loop.md) | Curator's role in the "Hermes" auto-improvement architecture |
| [`README.md`](https://github.com/akitaonrails/ai-memory/blob/main/README.md) (Curator section) | User-facing command documentation |

## Summary

- The **ai-memory curator** is strictly read-only—it detects issues without modifying data.
- Four finding types: **cold episodic** (low retention), **stale slots** (expired focus pages), **duplicate titles** (naming collisions), and **dangling cross-project links** (broken references).
- **Pinned pages** skip cold-episodic checks; **_pending/** pages skip duplicate-title detection.
- Reports can be emitted immediately or **staged for approval** without executing maintenance.
- All detection logic resides in [`crates/ai-memory-consolidate/src/curator.rs`](https://github.com/akitaonrails/ai-memory/blob/main/crates/ai-memory-consolidate/src/curator.rs) with explicit `dry_run` safety guarantees.

## Frequently Asked Questions

### Does the curator command modify any data in my project?

No. The curator is explicitly designed as a **report-only** tool. Per the `dry_run` flag and comments in `render_curator_report_markdown` (lines 64-68), even staged reports only create a markdown page containing the findings—no pages are edited, deleted, merged, or rewritten.

### How does the curator decide if an episodic page is "cold"?

The curator calculates a **retention score** using `retention_score_with_breadth` and compares it against `decay_params.cold_threshold`. Pages scoring below this threshold are flagged. Pinned pages (column-pinned or with `pinned: true` front matter) are excluded from this check.

### What threshold determines a "stale" slot page?

Two thresholds apply: **7 days** for [`_slots/current-focus.md`](https://github.com/akitaonrails/ai-memory/blob/main/_slots/current-focus.md) and **30 days** for all other slot pages. These are configurable via `current_focus_stale_days` and `other_slot_stale_days` parameters. The curator compares each slot's `updated_at` timestamp against these values.

### Can duplicate titles exist across different projects?

The **duplicate_title** finding only detects collisions **within the same project**. Cross-project title duplication is not flagged. Additionally, pages in `_pending/` directories are excluded from this check to avoid false positives from draft content.