Skip to main content
skill CX Codex

memory-hygiene · chrono-meta — Claude Code skill: detect stale agent memory

Spots memory entries that were true once and have drifted since. Ranks each by age and proposes a re-check or an archive move.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add chrono-meta/forge-harness --skill memory-hygiene -a claude-code
Open on GitHub

What memory-hygiene does

The skill walks the memory/*.md files and buckets every entry by type. Project entries go stale after 14 days, references and repo links after 30, operating rules after 90, user profile notes after 180. Age comes from metadata.modified when present, otherwise from the file's mtime; neither available means AGE-UNKNOWN, which is never treated as fresh.

Re-checking depends on the bucket. GitHub resources get a gh api call, DOIs and arXiv records go through WebFetch, project statuses are compared against the session starter file and recent git log. For rules the skill greps tracks/*/ for contradicting evidence from the last 30 days, and two or more hits send it to a human. A run log lands in tracks/_meta/memory_hygiene_<date>.md, which also arms the 7-day skip guard.

Nothing is deleted without a yes. Archive picks wait for confirmation, and before anything moves the skill snapshots every memory root the entry might live in. Memory kept outside $HOME/.claude/projects/*/memory and ./memory falls outside the scan on step one, so a run against those paths comes back empty.

What it helps with

  • catch an outdated project status before the agent cites it
  • re-check external links and DOIs stored in memory
  • find operating rules that recent sessions already contradict
  • clear a memory backlog without rereading every file
  • put memory checks on a schedule ahead of a harvest run

Example prompts for the agent

  • Check whether anything in memory has gone stale
  • Run memory-hygiene and list what needs re-verification
  • Audit memory and tell me what should be archived

How to install memory-hygiene

1Skills CLI (Vercel)

npx skills add chrono-meta/forge-harness --skill memory-hygiene -a claude-code

2Manually: put the files in place

~/.claude/skills/memory-hygiene/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/memory-hygiene/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about memory-hygiene

How do I install memory-hygiene in Claude Code?

Run npx skills add chrono-meta/forge-harness --skill memory-hygiene -a claude-code, then check ~/.claude/skills/memory-hygiene/SKILL.md.

What does memory-hygiene do?

It scans memory files, compares each entry's age against its type threshold, and re-verifies the stale ones: links, statuses, rules. You get a list of refreshed and drifted entries plus archive candidates.

Does it run on its own?

Yes, as the first step of a full harvest-loop run — provided the last scan was more than 7 days ago.

Source text

SKILL.md · MIT
---
name: memory-hygiene
description: Detects "stale-but-confident" memory entries — facts that were once verified but have silently drifted. Scans memory/*.md for entries past their staleness threshold and proposes re-verification or archival. Runs automatically as part of harvest-loop Step 0-c and on explicit invocation.
user-invocable: true
allowed-tools: ["Read", "Grep", "Glob", "Edit", "Bash"]
model: sonnet
---

# memory-hygiene — Stale Memory Detection and Re-Verification

> Addresses the "stale-but-confident" failure mode: verified information that silently drifts
> while remaining highly ranked in retrieval — identified as a harness failure mode
> in *Scaling the Harness in Agentic AI* (arXiv:2605.26112).
>
> **Sister asset**: arXiv:2607.01935 (*A-TMA: Decoupling State-Aware Memory Failures in Long-Term
> Agent Memory*, Shi/Tang/Tung 2026) names this exact class "ghost memory" — outdated / current /
> transitional facts intermixing during retrieval — and benchmarks it (LTP; conflict-accuracy +0.240,
> temporal-F1 0.03→0.17 on LoCoMo with a bank-maintenance layer). It is the tighter external frame for
> what memory-hygiene detects: this skill is the FH-native *detection + archival* pass over the same
> failure A-TMA formalizes at the retrieval layer. (Source-verified 2026-07-03; a broader bounded-memory
> testbed, arXiv:2607.02255 AgenticSTS, was considered and set aside — it targets context-assembly, not
> staleness, so it is not the sister here.)

FH is an online-first harness. Its memory entries point to live external resources (GitHub
repos, arXiv records, Zenodo DOIs, monitoring routines). These drift faster than in
offline systems — which makes hygiene both more necessary and more tractable (live
re-verification is possible).

## Trigger Conditions

### Natural Language Triggers

| Phrase | Intent |
|---|---|
| "memory check", "check stale memories" | Manual hygiene scan |
| "are my memories still accurate?" | Full re-verification pass |
| "clean up memory", "memory audit" | Propose archival candidates |
| "something in memory might be wrong" | Targeted re-check |

### Automatic Trigger

- **harvest-loop Step 0-c**: Runs automatically as the first step of every full harvest-loop
- **Cadence guard**: Skip if memory-hygiene ran within the last 7 days
  (`tracks/_meta/memory_hygiene_*.md` mtime check)

## Staleness Classification

| Type | Staleness Threshold | Re-verification Method |
|---|---|---|
| `project` — status/milestone entries | **14 days** | Re-read source file or live resource |
| `reference` — external URLs, DOIs, GitHub repos | **30 days** | WebFetch or gh CLI check |
| `feedback` — operating rules | **90 days** | Grep for contradicting evidence in recent sessions |
| `user` — user profile entries | **180 days** | Flag only, no auto-verification |

## Execution Steps

### Step 1 — Scan memory/*.md

Enumerate **every** root with a per-root state — an absent root and an empty root are different
facts, and the Step-4 snapshot scope is bound to this enumeration:

```bash
for ROOT in "$HOME"/.claude/projects/*/memory "$PWD/memory"; do
  if [ -d "$ROOT" ]; then
    n=$(ls "$ROOT"/*.md 2>/dev/null | wc -l | tr -d ' ')
    echo "EXISTS(n=$n) $ROOT"
  else
    echo "ABSENT       $ROOT"
  fi
done
```

**`ABSENT` is never counted as 0 entries.** Swallowing both into `2>/dev/null` makes "this root does
not exist here" indistinguishable from "this root is empty" — and the snapshot in Constraints below
must cover every root reported `EXISTS`, so a root mis-rendered as empty silently narrows the
snapshot scope.

For each file, extract:
- `metadata.type` from frontmatter
- **Age source, in this order** (measured over the live corpus, n=267): `metadata.modified`
  (ISO8601, present on 77/267) → else the file's filesystem mtime → else **`AGE-UNKNOWN`**.
  There is **no top-level `date:` field in this corpus** (measured 0/267) — do not look for one,
  and never treat `AGE-UNKNOWN` as fresh.
- Key factual claims (GitHub URLs, status strings, version numbers, dates)

### Step 2 — Classify by Staleness

Apply thresholds from the table above. Output a staleness roster:

```
STALE (>threshold):
  - api-migration-notes.md [feedback, 45d] — procedure may have changed
  - release-status.md [project, 16d] — status fields need live check
  - upstream-tracker.md [reference, 32d] — GitHub URL check needed

FRESH (<threshold):
  - user_role.md [user, 3d] — skip
  - fh-closed-loop-principle.md [feedback, 7d] — skip
```

### Step 3 — Re-verify Stale Entries

For each stale entry, run the appropriate re-verification:

**Reference type** (URLs, DOIs, GitHub):
- Use `gh api` for GitHub resources
- Use `WebFetch` for DOIs and arXiv records
- Mark `metadata.verified_at: YYYY-MM-DD` — **nested under `metadata:`**, the layer this corpus
  actually uses (`metadata:` present on 265/267; a top-level `verified_at` measured 0/267 and would
  be invisible to the Step-1 extractor)
- Flag `⚠ DRIFTED` if content has changed materially

**Project type** (status, milestones):
- Cross-check against `reference_next_session_starter.md` and recent git log
- Update or flag

**Feedback type** (rules):
- Grep `tracks/*/` for evidence contradicting the rule in last 30 days
- If 2+ contradictions found → flag for human review (do not auto-modify)

### Step 4 — Propose Actions (User Gate)

Present findings in this format:

```
memory-hygiene scan complete: N entries checked
  VERIFIED (no change needed): N
  UPDATED (refreshed verified_at): N
  ⚠ DRIFTED (content changed — needs human review): N
  📦 ARCHIVE CANDIDATE (no activity in Xd, superseded): N

Proposed changes:
  1. arxiv-submission-status.md — update status fields [auto-apply?]
  2. harness-federation-sync-plan.md — CLOSED flag still accurate? [confirm]
  ...

Apply updates? [y / N per item]
```

### Step 5 — Record Run

Use `printf`, never `echo "…\n…"` — `echo` expands `\n` in zsh but writes it **literally** in bash
(measured: 6 lines vs 1), which silently produces a one-line file with a broken frontmatter.

```bash
mkdir -p tracks/_meta
printf '%s\n' \
  '---' \
  "date: $(date +%Y-%m-%d)" \
  "entries_checked: ${ENTRIES_CHECKED}" \
  "demoted_to_archive: ${DEMOTED}" \
  "orphans_indexed: ${ORPHANS}" \
  "merged: ${MERGED}" \
  "drifted: ${DRIFTED}" \
  "hard_deleted: ${HARD_DELETED}" \
  '---' \
  > "tracks/_meta/memory_hygiene_$(date +%Y-%m-%d).md"
```

**Every count is a measured value from Steps 1–4.** A log still containing a literal `N` (or an
unexpanded `${…}`) is **an invalid log** — treat that run as not-recorded, because the log's
existence is what arms the 7-day cadence guard, so a placeholder log suppresses the *next* real run.

## Constraints

- **No auto-deletion**: Archive candidates are proposed, not deleted. Human confirmation required.
- **Snapshot before archive (Destructive-Op Gate for memory)**: before applying any confirmed
  archive/removal in Step 4, snapshot **every memory root the entry could live in** first — tar **all**
  roots Step 1 enumerated (`~/.claude/projects/*/memory/` AND hub-local `memory/`), not just one:
  the snapshot **must be gated on its own exit status** — an unwritable or missing `tracks/_meta`
  makes `tar` exit 1 and produce no tarball (measured), and without a gate the irreversible archive
  proceeds anyway:

  ```bash
  SNAP="tracks/_meta/memory_snapshot_$(date +%Y%m%d-%H%M%S).tgz"
  mkdir -p tracks/_meta || { echo "SNAPSHOT FAILED (mkdir) — abort archive"; exit 1; }
  tar czf "$SNAP" <each Step-1 root reported EXISTS> || { echo "SNAPSHOT FAILED (tar) — abort archive"; exit 1; }
  [ -s "$SNAP" ] || { echo "SNAPSHOT FAILED (empty tarball) — abort archive"; exit 1; }
  echo "SNAPSHOT OK: $SNAP"
  ```

  Only on `SNAPSHOT OK` may the archive proceed — so
  a wrong archive in any scanned root is one-command recoverable (a single-root snapshot can pass while
  the archived entry lived in the other root — bind the scope to the entry, not to "a tarball exists").
  Archive moves entries to a `.archive/` sibling, never hard-deletes (mirrors the Curator's
  tar-before-pass + rollback discipline; the Step 2 staleness thresholds are already the mechanical
  no-LLM pre-pass that the judged Step 3 re-verify sits on top of — order preserved: mechanical roster
  first, judged re-verify second).
- **Feedback type**: Never auto-modify feedback rules — flag only.
- **Simplification guard**: If 0 stale entries found, output one line "memory-hygiene: all fresh" and exit.
- **FH online advantage**: Unlike offline harnesses, FH can re-verify external references live.
  Use this — don't skip external checks.

## Done When

| Condition | Check class |
|---|---|
| Step 1~5 complete, every memory root reported `EXISTS(n=…)` or `ABSENT` | **mandatory-pass** |
| Staleness roster output (Step 2 = mechanical no-LLM pre-pass), with `AGE-UNKNOWN` entries listed separately and not as FRESH | **measured** (age from `metadata.modified` / mtime, not recall) |
| Re-verification run for all STALE entries | **mandatory-pass** |
| Each re-verified entry's verdict (VERIFIED / DRIFTED) is correct | **judged** — adversarial pairing: `fh-meta:fact-checker` re-greps the hub for the same claim; any disagreement downgrades the entry to DRIFTED (no judge-only PASS) |
| User gate presented and responded to (y/N per item) | **mandatory-pass** |
| If any archive confirmed: snapshot written **and its exit status checked** before the move (`tracks/_meta/memory_snapshot_*.tgz`, spanning every root reported `EXISTS`) | **mandatory-pass** — snapshot must cover the archived entry's dir; `SNAPSHOT OK` printed, not merely "a tarball exists" |
| Hygiene log written to `tracks/_meta/memory_hygiene_{date}.md` with real counts (no literal `N`, no unexpanded `${…}`) | **measured** |

## References

- Theoretical basis: *Scaling the Harness in Agentic AI* (arXiv:2605.26112) §Memory Problems — "stale-but-confident" failure mode
- Integrates with: `harvest-loop` Step 0-c · `context-doctor` (context layer hygiene)
- Memory format: `~/.claude/projects/*/memory/MEMORY.md`

© chrono-meta · MIT · chrono-meta/forge-harness

Similar skills

All skills for Agent setup: memory, context, orchestration →

memory-hygiene by other authors comes first.

From the same set13

qp-run Walks test cases from qp-plan against a running app through the session adapter and records a verdict for every step. Useful once the plan exists and someone has to execute it. CX Codex +1 ★ 30repo stars salience-splitter Splits an always-loaded context file into a thin resident layer and an on-demand layer. Useful once a SKILL.md or CLAUDE.md has grown past the point of being readable. CX Codex +1 ★ 30repo stars prompt-regression Compares edited harness files against a set of known-answer probes and reports PASS, FAIL or SKIP for each. Useful right after you touch rules, CLAUDE.md or add a skill. CX Codex +1 ★ 30repo stars phantom-quench Flags claims in reports, test cases and design docs that the source files do not back up. Catches phantom numbers and unsupported citations. CX Codex +1 ★ 30repo stars install-doctor Scans your project before and after meta-harness plugin installs to surface duplicates, overlaps and silent overwrite risks. CX Codex +1 ★ 30repo stars harness-doctor Walks through your harness files and reports what is missing, stale or pointing nowhere. Useful once project instructions pile up and the agent starts guessing. CX Codex +1 ★ 30repo stars field-harvest A skill that mines a project's git history for patterns worth moving into the main harness, and writes session notes into the knowledge hub when work wraps up. CX Codex +1 ★ 30repo stars deep-clarify Turns a fuzzy request into a written specification by asking about the goal, the finish line and the limits, then saving the result to a file. CX Codex +1 ★ 30repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor