Skip to content
Agent Orchestration
Skill

/audit-memory

Audit Claude's saved memories for claims that no longer hold true — verify each against current code, PRs and tickets, then archive the stale ones with your approval, and name the MCPs needed for anything unverifiable.

BOOST
From plugin
2x-skills
24710 skills
Install
$ npx -y skills add intercom/2x-skills --skill audit-memory --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/audit-memory

Context preview

The summary Claude sees to decide when to auto-load this skill.

Audit Claude's saved memories for claims that no longer hold true — verify each against current code, PRs and tickets, then archive the stale ones with your approval, and name the MCPs needed for anything unverifiable.

SKILL.md

audit-memory.SKILL.md
name: audit-memory
description: |
  Audit Claude's saved memories for claims that no longer hold true — verify each against current code, PRs and tickets, then archive the stale ones with your approval, and name the MCPs needed for anything unverifiable.
disable-model-invocation: true
allowed-tools: Bash Read Grep Glob Edit Write AskUserQuestion Agent
metadata:
  user-invocable: true
  argument-hint: "[project name to audit] [--root <memory-root>]"

Audit Memory

Saved memories are point-in-time observations. Code moves, PRs merge, projects finish — and a memory that was true when written silently becomes a confidently wrong instruction to every future session. This skill verifies memories against reality and archives what no longer holds.

**Never auto-fires** — it archives user data, so it runs only when someone types `/audit-memory`.

Core guarantees

These are load-bearing. Violating any of them makes the skill untrustworthy:

1. **Absence of evidence is never evidence of staleness.** A claim you cannot check is `NEEDS-<tool>`, `NOT-ATTEMPTED` or `NOT-CHECKABLE` — never stale, never offered for removal. A disconnected MCP must never turn valid memories into deletion candidates. Two mirrors of this also hold. Never report a check you skipped as a tool that was missing. And never over-apply it: a newer memory stating the old fact was removed **is** positive evidence, sufficient alone — an unreachable repo cannot demote it, because the evidence was never in the repo. 2. **Archive before you touch anything, so nothing is unrecoverable.** Memory files are not version-controlled and have no trash. Snapshot the original into the archive before *any* write or removal — claim removals, whole-file archiving, `MEMORY.md` pointer sync, and `lastReviewed` stamps alike. Removal does mean deleting the file; it is safe only because the verified snapshot precedes it. 3. **Preferences are not claims.** `type: feedback` and `type: user` memories are standing instructions. Never argue they are false — the user is the only authority on whether a preference still applies. 4. **No writes outside the resolved roots.** Only the memory root and archive root are ever written to. 5. **Name the root you actually audited**, before showing findings, and never claim you honoured `CLAUDE_MEMORY_ROOT` unless you read it. Auditing a different corpus than the caller meant is the worst failure here.

Step 1 — Resolve roots and discover projects

Run this **exactly as written, as a single call**. It resolves both roots and lists every project in one step.

The memory root resolves in this order: an explicit `--root <path>` argument, then `CLAUDE_MEMORY_ROOT`, then `~/.claude/projects`. If the caller passed `--root <path>`, prefix the block with `CLAUDE_MEMORY_ROOT='<path>' ` so both routes land in the same variable.

**Single-quote it, and escape any single quote inside it** by replacing each `'` with `'\''`. Unquoted, a space or metacharacter splits the path; naively quoted, an apostrophe closes the quote early and the rest runs as shell. A path you cannot quote safely is one you refuse, not one you guess at.

Shell variables do not survive between Bash calls, so never split root resolution from the work that uses it, and never pass a root in as `"$MEM_ROOT"` from an earlier call — it will be empty, which is why this block reads the environment directly.

**If this block runs and fails, stop and report the error** — a nonexistent root, a permission error, a traceback. Never retry against `$HOME/.claude/projects` instead (guarantee 5).

`Bash` being unavailable is different — the block never runs, so `CLAUDE_MEMORY_ROOT` is unreadable and you cannot know whether the default root is the intended corpus. That run is **read-only until the root is confirmed**: report findings against `~/.claude/projects`, say which root you used and that the environment was invisible, and make **no write at all** — no archive, no edit, no stamp — until the user confirms it. Findings can be discarded; an archive written against the wrong corpus cannot.

**Never decode project directory names into filesystem paths.** The encoding is lossy: `-Users-me-src-claude-plugins` could be `src/claude-plugins` or `src/claude/plugins`, because path separators and literal hyphens both become `-`. The authoritative `cwd` comes from the project's session transcripts, which is what this block reads.

**If `Bash` is unavailable, do not stop** — fall back to the tool-only path below. Sandboxes and eval harnesses routinely deny `Bash`, and a discovery step with no fallback turns that into a dead end.

python3 <<'PY'
import glob, json, os, re, subprocess, time

root = os.environ.get("CLAUDE_MEMORY_ROOT") or os.path.expanduser("~/.claude/projects")
# expanduser before resolving: --root is single-quoted, so a leading ~ reaches
# Python literally and would otherwise resolve against the cwd. realpath, not
# abspath, so a symlinked root cannot place the archive outside the resolved
# roots the no-external-writes guarantee is stated against.
root = os.path.realpath(os.path.expanduser(root))
archive = os.path.join(os.path.dirname(root), "memory-archive",
                       time.strftime("%Y-%m-%d"))
print("MEMORY_ROOT=" + root)
print("ARCHIVE_ROOT=" + archive)
print("SOURCE=" + ("CLAUDE_MEMORY_ROOT" if os.environ.get("CLAUDE_MEMORY_ROOT") else "default"))
if not os.path.isdir(root):
    raise SystemExit("memory root does not exist: " + root)

for d in sorted(os.listdir(root)):
    mem = os.path.join(root, d, "memory")
    if not os.path.isdir(mem):
        continue
    # glob.escape the directory: a project dir holding [ ] * or ? would otherwise be
    # read as a pattern and match the wrong memories, or none.
    files = [f for f in glob.glob(glob.escape(mem) + "/*.md")
             if os.path.basename(f) != "MEMORY.md"]
    if not files and not os.path.exists(os.path.join(mem, "MEMORY.md")):
        continue
    cwd = None
    for j in sort
Read more
Ships with2x-skills

A marketplace of Claude Code skills built by the Fin 2x team.

Get the whole plugin

Other skills on 2x-skills.