save-memories · git:20260805.f5d6afa · 2026-08-05 · sha256 7dd79c75847a2d9a
save-memories git:20260805.f5d6afaA
Immutable. This exact content is served forever at /api/v1/blob/7dd79c75847a2d9a.
---
name: save-memories
description: Save important memories from this conversation to the cc-memory database via the anti-patch upsert path (merge / supersede / insert based on similarity to existing memories).
---
## Save Memories to cc-memory Database
Review the current conversation and persist **structured memories** through the
**anti-patch writer** (`llm.memory_writer.upsert_smart`). Never bypass this path:
it auto-decides whether to MERGE (overwrite an existing high-similarity memory),
SUPERSEDE (archive an old version and insert a refined one with a chain link),
or INSERT (genuinely new fact). This prevents stacked duplicates.
### Step 1 — Review the conversation
Identify, since the last save or session start:
- **Decisions** made (architecture choices, parameter selections, tradeoffs)
- **Results** (measurements, benchmarks with specific numbers + units)
- **Bugs** found and fixed (root cause + fix; especially "NEVER do X" warnings)
- **Config** changes (hyperparameters, env vars, settings that were tuned)
- **Architecture** insights (module structure, pipeline design, data flow)
- **Tasks** still pending or blocked
### Step 2 — Score each candidate
- `category`: one of `decision`, `result`, `config`, `bug`, `task`, `arch`, `note`
- `importance`: 1-5 (5=critical/never-forget, 4=important, 3=useful, 2=minor, 1=skip)
- `content`: one self-contained sentence with **specific values** (numbers, file
paths, parameter names). Bad: "tuned the learning rate". Good: "lr=3e-4 picked
over 1e-3 because val_loss flatlined after epoch 8."
- `topic`: a short lowercase keyword for grouping (e.g. `auth`, `pipeline`, `ui`)
### Step 3 — Quality bar
- Only **conclusions**, not the discussion process
- Each memory must be understandable WITHOUT the conversation
- 5-15 memories per call (quality > quantity)
- Skip: tool errors, navigation, meta-discussion, conversation logistics
- Do NOT save memories ABOUT the memory plugin itself unless it's a critical bug
### Step 4 — Run this exact command
The writer handles dedup, similarity-based reconcile, and MEMORY.md regen
automatically. Do not call `db.insert_memory` directly.
```bash
python3 -c "
import json, os, sys
from pathlib import Path
# why: the old hardcoded ~/.claude/hooks/cc-memory/cc_memory path made this
# skill dead on every install that is not a v2.0-era standalone one -- on a
# marketplace install that directory holds only logs/. Probe BOTH layouts:
# nested - marketplace / dev checkout: <root>/cc_memory/core/db.py
# flat - standalone installer output: <root>/core/db.py
# (ui/installer.py copies each subpackage to TARGET_DIR/<subdir>/ directly.)
def _pkg_dir(root):
if root and (Path(root) / 'cc_memory' / 'core' / 'db.py').exists():
return Path(root) / 'cc_memory'
if root and (Path(root) / 'core' / 'db.py').exists():
return Path(root)
return None
def _find_pkg_dir():
cand = [os.environ.get('CLAUDE_PLUGIN_ROOT')]
s = Path.home() / '.claude' / 'settings.json'
if s.exists():
try:
# utf-8-sig, not utf-8: PowerShell's > and Out-File write a UTF-8 BOM
# by default, and json.loads rejects it. Reading this file as plain
# utf-8 made THIS skill print 'cannot locate the cc-memory package
# tree' on a healthy marketplace install while /ccm-load reported
# ACTIVATED on the SAME machine - only the encoding differed.
# ui/installer.py:_read_settings and skills/ccm-load/SKILL.md both
# already use utf-8-sig, with the same comment.
mk = json.loads(s.read_text(encoding='utf-8-sig')).get('extraKnownMarketplaces', {}).get('cc-memory') or {}
cand.append((mk.get('source') or {}).get('path'))
except (json.JSONDecodeError, OSError):
# why: a malformed settings.json must not abort resolution -- the
# standalone candidate appended below can still succeed
cand.append(None)
cand.append(str(Path.home() / '.claude' / 'hooks' / 'cc-memory'))
for c in cand:
d = _pkg_dir(c)
if d:
return d
return None
PKG = _find_pkg_dir()
if PKG is None:
print('[error] cannot locate the cc-memory package tree; run /ccm-load first.')
sys.exit(0)
sys.path.insert(0, str(PKG.resolve()))
from core.db import MemoryDB
from llm.memory_writer import upsert_batch
project = str(Path('.').resolve())
db = MemoryDB(Path(project) / 'memory' / 'memory.db')
pid = db.upsert_project(project)
memories = [
# {'category': 'decision', 'content': '...', 'importance': 4, 'topic': 'auth'},
# ADD MEMORIES HERE — see Step 2 for fields
]
counts = upsert_batch(db, pid, None, memories, memory_dir=Path(project) / 'memory')
print(f\"inserted={counts.get('inserted',0)} \"
f\"merged={counts.get('merged',0)} \"
f\"superseded={counts.get('superseded',0)} \"
f\"skipped={counts.get('skipped',0)}\")
"
```
### Step 5 — Report results
Tell the user the breakdown:
- **Inserted**: brand-new facts
- **Merged**: refined an existing high-similarity memory in place
- **Superseded**: replaced an older version of the same fact (preserved as chain)
- **Skipped**: exact duplicates already present
The merged/superseded counts are *good*: they mean the writer is preventing the
patch-style stacking the v2.1 anti-patch contract was designed to stop. See
`docs/CONTRACTS.md#anti-patch-contract` for the full contract.