REM sleep for Claude Code's native memory — on-demand consolidation: dedupe, resolve contradictions, archive stale facts, rebuild a lean index.
SaferSkills independently audited memrem (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are running a memory consolidation pass ("REM sleep") over Claude Code's native markdown memory for the current project. You groom the memory dir so it stays lean, non-contradictory, and matched to reality — without losing anything (archive, never hard-delete).
memory/ directory and MEMORY.mdindex inside it, plus a memrem-owned sidecar memory/_memrem/ and archive memory/_archive/. Touch nothing else in the repo.
$ARGUMENTS. If thosearguments include --confirm or --dry-run, run in confirm/dry-run mode: do everything read-only, present a PLAN, then stop and wait for approval. Otherwise (no such flag), run in apply mode — apply changes directly (the operation is archive-not-delete and the dir is typically git-recoverable, so direct apply is safe).
(git log, ls, grep, python3 to read/parse transcripts) — but never for network calls, installing anything, hard-deleting memory, or writing outside the memory dir.
The native memory dir for the current project is at: ~/.claude/projects/<project-slug>/memory/
where <project-slug> is the current working directory path with / replaced by - (e.g. /home/me/projects/app → -home-me-projects-app; note the leading dash because the absolute path starts with /). The index is MEMORY.md in that dir; topic files are sibling .md files. If you cannot resolve the slug, ask the user to confirm the path rather than guessing. If the dir or MEMORY.md does not exist, treat it as an empty first run (Phase 1 handles this).
MEMORY.md is absent, this is a first/empty run: there isnothing to consolidate yet — create a minimal MEMORY.md if missing, write the sidecar marker (see shape below), and report "nothing to consolidate." Do not scan transcripts on a truly empty dir.
*.md in the memory dir (skip _archive/ and _memrem/ for content, butread _archive/ tombstone headers — frontmatter only — into context).
memory/_memrem/state.json if present. Its shape is: {"last_consolidated": "2026-06-13", "last_consolidated_epoch": 1781740800}Note last_consolidated_epoch — you pass it to the extractor in Phase 2. If the file is absent (first run), default the transcript window to the last 7 days (--days 7).
before writing (concurrency guard): if any changed underneath you, abort with a message rather than clobber another session's write.
Goal: find new facts, corrections, decisions, and preferences from recent sessions that should be reflected in memory.
/tmp). The skill ships scripts/extract_transcripts.py, which reads the project's *.jsonl within a recency window, extracts USER / ASSISTANT / (scrubbed) tool-result text, and redacts secrets on ingest. Invoke it via the skill-dir variable so it resolves regardless of cwd:
python3 "${CLAUDE_SKILL_DIR}/scripts/extract_transcripts.py" \
~/.claude/projects/<project-slug>/ --days 7When a last_consolidated_epoch exists in state.json, pass it as --since-epoch <epoch> instead of --days 7, so the window starts exactly there. (Pass the epoch number, not the ISO date — --since-epoch takes epoch seconds.) The script does best-effort mechanical redaction of common credential shapes (API keys, provider tokens, JWTs, PEM blocks, connection strings, .env-style assignments, Authorization/Bearer, high-entropy hex, emails) before any content reaches you. It is not a guarantee — stay alert for anything secret-like the regexes missed and drop it.
output, never carry into memory: patient names, patient IDs, diagnoses, dates of birth, national IDs, or contact info — even summarized or derived. When in doubt, drop it. Keep a running count of secret/PHI candidates you drop, for the final summary — never store the content itself anywhere.
_archive/marked reason: contradicted or reason: rejected. "Match" = lexical, not semantic: case-insensitive comparison after collapsing internal whitespace to single spaces and stripping leading/trailing punctuation. Do NOT do fuzzy/semantic matching — if the wording differs materially, treat it as a new fact (a human can re-archive it). Those tombstones were deliberately invalidated; do not bring them back.
(user | feedback | project | reference).
No stray temp files. Use the bundled script (orRead/Grepdirectly). Do not write helper scripts or extracted content to/tmpor anywhere outside the memory dir. If you ever need a scratch file, put it undermemory/_memrem/and remove it before finishing.
Working on the in-memory set of existing facts + clean candidates:
complete phrasing. Convert relative dates ("yesterday", "next week") to absolute dates.
fact, and move the old one to `_archive/` with a tombstone (reason: contradicted, superseded_by: pointing at the winner). Never silently overwrite — the loser always leaves a tombstone.
(reason: redundant).
YYYY-MM-DD).name/slug, ascending.name, description, metadata.type)exactly. Do not invent new frontmatter keys in v1 (scoring/decay is v1.1).
credential redaction over the candidate text one more time. The ingest scrub is the first gate; this is the second, at the write boundary. PHI still rides on your judgment (step Phase 2.2) — do not write patient identifiers even if they slipped the regexes.
(- [Title](file.md) — one-line hook). Group order is fixed: user, then feedback, then project, then reference, then any other types alphabetically. Within a group, sort by title ascending. One blank line between groups, none between entries. Hard targets: < 200 lines AND < 25 KB (only the first 200 lines / 25 KB load at session start — anything beyond is dead weight). If you exceed it, the memory set itself is too large → flag it, don't pad.
memory/_archive/. Each tombstone keeps itsfrontmatter and appends: archived: <date>, reason: stale|contradicted|redundant|rejected, and superseded_by: if merged.
contradicted | rejected tombstones: keep permanently, but strip the body (header-only)once older than 90 days.
stale | redundant tombstones: remove once older than 180 days.anything — leave the dir byte-identical (this is what makes a second run idempotent).
once, immediately before the first write. If any mtime changed, abort before writing and tell the user another session modified memory mid-run. If clean, perform all writes in one batch without re-stating between them.
memory/_memrem/state.json with both the new last_consolidated (ISO date) andlast_consolidated_epoch (epoch seconds). This marker lives in the sidecar — never in MEMORY.md (rebuilt) or a memory file (Claude may clobber it).
After applying (or, in --confirm mode, as the PLAN), report a concise summary:
In --confirm / --dry-run mode, end with: "No changes written. Reply to approve and I'll apply this plan." and wait.
MEMORY.md + sidecar; report.somewhere arbitrary.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.