executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
memory-hygieneDetects "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.
Independent GitHub snapshot · Automated classification · Original documentation governs
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).
| 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 |
tracks/_meta/memory_hygiene_*.md mtime check)| 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 |
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:
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 frontmattermetadata.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.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
For each stale entry, run the appropriate re-verification:
Reference type (URLs, DOIs, GitHub):
gh api for GitHub resourcesWebFetch for DOIs and arXiv recordsmetadata.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)⚠ DRIFTED if content has changed materiallyProject type (status, milestones):
reference_next_session_starter.md and recent git logFeedback type (rules):
tracks/*/ for evidence contradicting the rule in last 30 daysPresent 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]
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.
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.
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:
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.
| 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 |
harvest-loop Step 0-c · context-doctor (context layer hygiene)~/.claude/projects/*/memory/MEMORY.md