Claude Skill

memory-factcheck

Fact-check an agent's persistent memory against ground truth — verify each memory's load-bearing claims against code, database, issue tracker and filesystem, correct the stale ones, and report dead ones as archive candidates. Use when memory grows past ~30 files, right after a bi

LLM Mart · 0 points · 15 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download leeyudok-agents-scaffold-presets_lang-en_base_.claude_skills_memory-factcheck-1b2f034.zip · 4 KB
Part of leeyudok/agents-scaffold — 32 skills

Install

skills CLI npx skills add https://github.com/LeeYudok/agents-scaffold/tree/main/presets/lang-en/base/.claude/skills/memory-factcheck
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install leeyudok-agents-scaffold@llmmart
Git git clone https://github.com/LeeYudok/agents-scaffold.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole leeyudok/agents-scaffold collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Memory Fact-Check

Origin: the skill of the same name in leeyudok/doksam-skills. Deliberately forked for template bundling — not auto-synced; good improvements are cherry-picked manually.

Memory decays. A fact that was true when written becomes false as code, schema and infrastructure move on. Stale memory is worse than no memory — an agent reads it and confidently does the wrong thing.

This is not a structural hygiene pass. Orphan files, duplicate entries, index bloat, broken internal links — those checks compare memory files to each other. This skill compares each memory to the world it describes: the code, the database, the issue tracker, the filesystem. A memory can be perfectly well-formed, correctly indexed, recently touched — and completely false.

Automatic deletion is forbidden. Only a source-of-truth comparison can tell what is dead, and losing an incident lesson is expensive. Hence semi-automatic: correct freely, archive only with approval, never delete.

1. Locate and inventory

Find the memory set. Common locations, in order:

  • a path declared by the project's agent instructions (AGENTS.md / CLAUDE.md — e.g. "memory SSOT is .claude/memory/"). A declared path wins over every default.
  • .claude/memory/ in the repo (team-shared, committed)
  • the host's per-project memory dir (e.g. ~/.claude/projects/<slug>/memory/)

Collect for each file: frontmatter (name/description/type), and last modification date (git log -1 --format=%cs -- <file> for committed memory, stat otherwise). Note the index file (MEMORY.md) if one exists — it is audited too, but it is an index, not a memory.

Personal files are out of scope — anything the project marks personal (user_*.md or equivalent) belongs to its owner. Leave untouched.

Reading many files: dumping 50 memories into context at once blows the tool output cap and wastes the budget. Concatenate to one scratch file with ########## <filename> headers, then page through it. Do not skim — a stale claim is usually one clause inside an otherwise correct paragraph.

2. Extract load-bearing claims

Per file, pick the 1–3 claims that change what an agent would do. Ignore prose, rationale and background; a memory is only as stale as its actionable assertions.

Load-bearing looks like: "X lives at path P" · "table T has N rows" · "issue #N is still open" · "feature F does not exist yet" · "library L is not installed" · "the fix for this is still pending" · "run command C to verify".

3. Verify against the source of truth

Work cheapest-and-highest-yield first. In practice the ranking below holds: issue status is one API call and catches the largest share of stale claims, because memories are written mid-work and the work then finishes without anyone going back to edit the memory.

Order Claim type How to verify
1 Issue/PR state ("#N open", "waiting on #N", "decision pending") forge CLI/API — gh issue view N --json state / glab api projects/<enc>/issues/N. Batch them in one loop
2 Path/URL (script locations, deploy paths, endpoints) ls, test -f, curl -s -o /dev/null -w '%{http_code}'
3 Code (file/class/config exists, behaves a certain way) grep/Read the current tree — the code is the SoT, not the memory
4 Data/schema (tables, columns, row counts) read-only queries via the project's DB tool. Prefer catalog estimates first (pg_class.reltuples, information_schema.columns), exact count(*) only when the estimate is the disputed claim
5 Runtime/host (cron jobs, services, logs) ssh <host> 'ls …; crontab -l; tail <log>' — a job's last log line dates the claim precisely

Parallelize independent verifications. If a source is unreachable, say so explicitly in the report — never silently downgrade "couldn't check" to "checked".

4. Classify

  • fresh — every claim holds. Don't touch it.
  • stale — some claim is outdated (moved path, changed number, closed issue, implemented gap). → Correct the body now, with the measured value and the date. Corrections are within autonomous scope; they are additive truth, not deletion.
  • dead — the core premise is gone (library removed, feature retired, wholly superseded). → Mark as an archive candidate only.

5. Stale patterns worth hunting

Beyond "the number changed", these recur and are easy to miss:

  • Fixed-gap drift — the memory documents a missing capability ("there is no startup reconcile", "no rate limiting yet") and it has since been built. This is the most dangerous class: the agent re-implements or re-reports work that already shipped. Check the linked issue and grep for the symbol.
  • Cross-memory contradiction — two memories disagree (one says a script is the way to do X, another says that script was retired). At least one is stale by definition. Compare claims across files, not only file-by-file.
  • Scale drift — "table T has ~8M rows" written months ago now off by 25%. Harmless as trivia, harmful when the memory derives advice from it (batch sizes, timeout budgets, "this query takes 19s").
  • Recipe rot — the memory stores a command/query as a verified recipe, and the recipe no longer works at today's data volume or API version. Re-run stored recipes; a recipe you did not execute is unverified.
  • Progress-state drift — a long-running job/backfill memory whose "current status" section is weeks behind, sometimes with two internally contradictory status sections stacked up. Date each section, keep the newest, mark superseded ones.
  • Identity mismatch — name/description says one thing, the body says the opposite (e.g. a file named *-via-toolX whose body records that toolX was abandoned). Recall matches on description, so the file gets loaded for the wrong reason, or missed entirely.

6. Report, then apply

Report as a table before changing anything — file · class · one-line evidence · action:

File Class Evidence Action
reference_x.md stale script moved scripts/ → data/ path corrected
project_y.md stale claims "#302 reconcile missing"; JobRunHistoryReconciler exists, #302 closed rewritten as done
project_z.md dead candidate feature from #N removed in #M awaiting approval

Then:

  1. Apply corrections to stale bodies — measured value + date, keeping the original observation where it still carries a lesson ("was 8M as of
  2. Archive dead candidates only after explicit user approval: git mv into <memory>/archive/ and add archived: <date> <reason> to the frontmatter. Never rm.
  3. Sync the index — reflect corrections, drop archived entries from MEMORY.md.
  4. Commit through the project's normal workflow (issue → branch/worktree → PR/MR). Memory is team-shared content; it does not get direct-to-main commits.

Judgment rules — stay conservative

  • Unverifiable ⇒ fresh. If the source of truth is unreachable, leave the memory alone and say the check was skipped. Unknown is not dead.
  • Incident lessons stay fresh even when the code moves. A memory recording why something broke exists to prevent recurrence, not to snapshot a call site. Correct its stale path references; do not retire the lesson because the file was renamed.
  • Report the drift, don't invent the cause. If a count inverted or a number moved inexplicably, record the measurement and flag it as unexplained. A plausible story written into memory becomes tomorrow's false fact.
  • Prefer merge over create. Two memories on one topic → propose merging into the existing one.
  • Non-obvious facts discovered by the audit itself become new memories — the audit is itself a source of ground truth.

Field notes

  • Fresh timestamps prove nothing. A file committed this week can carry a claim that was already false when written; a file untouched for months can be perfectly true. Verify claims, never sort by date and trim the tail.
  • count(*) on a large table may exceed the DB tool's statement timeout — that failure is a finding when the memory claims the query is fast.
  • Quote globs when shelling out from zsh (grep --include="*.java"), or the shell eats them and the check silently returns nothing — a false "fresh".
  • An issue being closed does not by itself prove the described work shipped. For fixed-gap claims, confirm with a grep for the symbol as well.
Files (agents-scaffold)
  • SKILL.md 9 KB
    ---
    name: memory-factcheck
    description: Fact-check an agent's persistent memory against ground truth — verify each memory's load-bearing claims against code, database, issue tracker and filesystem, correct the stale ones, and report dead ones as archive candidates. Use when memory grows past ~30 files, right after a big stack/infra change (library swap, version upgrade, server migration, schema drop), when two memories seem to contradict each other, or on a "clean up / audit my memory" request.
    ---
    
    # Memory Fact-Check
    
    > Origin: the skill of the same name in [leeyudok/doksam-skills](https://github.com/leeyudok/doksam-skills).
    > **Deliberately forked** for template bundling — not auto-synced; good improvements are cherry-picked manually.
    
    Memory decays. A fact that was true when written becomes false as code, schema and
    infrastructure move on. **Stale memory is worse than no memory** — an agent reads it and
    confidently does the wrong thing.
    
    This is **not** a structural hygiene pass. Orphan files, duplicate entries, index bloat,
    broken internal links — those checks compare memory files *to each other*. This skill
    compares each memory **to the world it describes**: the code, the database, the issue
    tracker, the filesystem. A memory can be perfectly well-formed, correctly indexed, recently
    touched — and completely false.
    
    Automatic deletion is forbidden. Only a source-of-truth comparison can tell what is dead,
    and losing an incident lesson is expensive. Hence semi-automatic: **correct freely, archive
    only with approval, never delete.**
    
    ## 1. Locate and inventory
    
    Find the memory set. Common locations, in order:
    
    - a path declared by the project's agent instructions (`AGENTS.md` / `CLAUDE.md` — e.g.
      "memory SSOT is `.claude/memory/`"). A declared path wins over every default.
    - `.claude/memory/` in the repo (team-shared, committed)
    - the host's per-project memory dir (e.g. `~/.claude/projects/<slug>/memory/`)
    
    Collect for each file: frontmatter (`name`/`description`/`type`), and last modification date
    (`git log -1 --format=%cs -- <file>` for committed memory, `stat` otherwise). Note the index
    file (`MEMORY.md`) if one exists — it is audited too, but it is an index, not a memory.
    
    **Personal files are out of scope** — anything the project marks personal (`user_*.md` or
    equivalent) belongs to its owner. Leave untouched.
    
    **Reading many files**: dumping 50 memories into context at once blows the tool output cap
    and wastes the budget. Concatenate to one scratch file with `########## <filename>` headers,
    then page through it. Do not skim — a stale claim is usually one clause inside an otherwise
    correct paragraph.
    
    ## 2. Extract load-bearing claims
    
    Per file, pick the **1–3 claims that change what an agent would do**. Ignore prose, rationale
    and background; a memory is only as stale as its actionable assertions.
    
    Load-bearing looks like: "X lives at path P" · "table T has N rows" · "issue #N is still open"
    · "feature F does not exist yet" · "library L is not installed" · "the fix for this is still
    pending" · "run command C to verify".
    
    ## 3. Verify against the source of truth
    
    Work **cheapest-and-highest-yield first**. In practice the ranking below holds: issue status
    is one API call and catches the largest share of stale claims, because memories are written
    mid-work and the work then finishes without anyone going back to edit the memory.
    
    | Order | Claim type | How to verify |
    | --- | --- | --- |
    | 1 | **Issue/PR state** ("#N open", "waiting on #N", "decision pending") | forge CLI/API — `gh issue view N --json state` / `glab api projects/<enc>/issues/N`. Batch them in one loop |
    | 2 | **Path/URL** (script locations, deploy paths, endpoints) | `ls`, `test -f`, `curl -s -o /dev/null -w '%{http_code}'` |
    | 3 | **Code** (file/class/config exists, behaves a certain way) | `grep`/`Read` the current tree — *the code is the SoT, not the memory* |
    | 4 | **Data/schema** (tables, columns, row counts) | read-only queries via the project's DB tool. Prefer catalog estimates first (`pg_class.reltuples`, `information_schema.columns`), exact `count(*)` only when the estimate is the disputed claim |
    | 5 | **Runtime/host** (cron jobs, services, logs) | `ssh <host> 'ls …; crontab -l; tail <log>'` — a job's last log line dates the claim precisely |
    
    Parallelize independent verifications. If a source is unreachable, say so explicitly in the
    report — never silently downgrade "couldn't check" to "checked".
    
    ## 4. Classify
    
    - **fresh** — every claim holds. Don't touch it.
    - **stale** — some claim is outdated (moved path, changed number, closed issue, implemented
      gap). → **Correct the body now, with the measured value and the date.** Corrections are
      within autonomous scope; they are additive truth, not deletion.
    - **dead** — the core premise is gone (library removed, feature retired, wholly superseded).
      → Mark as an archive **candidate** only.
    
    ## 5. Stale patterns worth hunting
    
    Beyond "the number changed", these recur and are easy to miss:
    
    - **Fixed-gap drift** — the memory documents a missing capability ("there is no startup
      reconcile", "no rate limiting yet") and it has since been built. This is the most dangerous
      class: the agent re-implements or re-reports work that already shipped. Check the linked
      issue *and* grep for the symbol.
    - **Cross-memory contradiction** — two memories disagree (one says a script is the way to do
      X, another says that script was retired). At least one is stale by definition. Compare
      claims across files, not only file-by-file.
    - **Scale drift** — "table T has ~8M rows" written months ago now off by 25%. Harmless as
      trivia, harmful when the memory derives advice from it (batch sizes, timeout budgets,
      "this query takes 19s").
    - **Recipe rot** — the memory stores a command/query as a verified recipe, and the recipe no
      longer works at today's data volume or API version. **Re-run stored recipes**; a recipe you
      did not execute is unverified.
    - **Progress-state drift** — a long-running job/backfill memory whose "current status" section
      is weeks behind, sometimes with two internally contradictory status sections stacked up.
      Date each section, keep the newest, mark superseded ones.
    - **Identity mismatch** — `name`/`description` says one thing, the body says the opposite
      (e.g. a file named `*-via-toolX` whose body records that toolX was abandoned). Recall
      matches on description, so the file gets loaded for the wrong reason, or missed entirely.
    
    ## 6. Report, then apply
    
    Report as a table before changing anything — file · class · one-line evidence · action:
    
    | File | Class | Evidence | Action |
    | --- | --- | --- | --- |
    | `reference_x.md` | stale | script moved `scripts/` → `data/` | path corrected |
    | `project_y.md` | stale | claims "#302 reconcile missing"; `JobRunHistoryReconciler` exists, #302 closed | rewritten as done |
    | `project_z.md` | dead candidate | feature from #N removed in #M | awaiting approval |
    
    Then:
    
    1. **Apply corrections** to stale bodies — measured value + date, keeping the original
       observation where it still carries a lesson ("was 8M as of <date>, 9.9M as of <today>").
    2. **Archive dead candidates only after explicit user approval**: `git mv` into
       `<memory>/archive/` and add `archived: <date> <reason>` to the frontmatter. Never `rm`.
    3. **Sync the index** — reflect corrections, drop archived entries from `MEMORY.md`.
    4. **Commit through the project's normal workflow** (issue → branch/worktree → PR/MR). Memory
       is team-shared content; it does not get direct-to-main commits.
    
    ## Judgment rules — stay conservative
    
    - **Unverifiable ⇒ fresh.** If the source of truth is unreachable, leave the memory alone and
      say the check was skipped. Unknown is not dead.
    - **Incident lessons stay fresh even when the code moves.** A memory recording *why something
      broke* exists to prevent recurrence, not to snapshot a call site. Correct its stale path
      references; do not retire the lesson because the file was renamed.
    - **Report the drift, don't invent the cause.** If a count inverted or a number moved
      inexplicably, record the measurement and flag it as unexplained. A plausible story written
      into memory becomes tomorrow's false fact.
    - **Prefer merge over create.** Two memories on one topic → propose merging into the existing
      one.
    - **Non-obvious facts discovered by the audit itself become new memories** — the audit is
      itself a source of ground truth.
    
    ## Field notes
    
    - Fresh timestamps prove nothing. A file committed this week can carry a claim that was
      already false when written; a file untouched for months can be perfectly true. Verify
      claims, never sort by date and trim the tail.
    - `count(*)` on a large table may exceed the DB tool's statement timeout — that failure *is*
      a finding when the memory claims the query is fast.
    - Quote globs when shelling out from zsh (`grep --include="*.java"`), or the shell eats them
      and the check silently returns nothing — a false "fresh".
    - An issue being closed does not by itself prove the described work shipped. For fixed-gap
      claims, confirm with a grep for the symbol as well.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related