Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add skills/skymanbp/cc-memory/save-memoriesnpx skills add skymanbp/cc-memory --skill save-memoriesgit clone --depth 1 https://github.com/skymanbp/cc-memoryWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/skymanbp/cc-memory/save-memories)<a href="https://agentmods.dev/skills/skymanbp/cc-memory/save-memories"><img src="https://agentmods.dev/badge/skills/skymanbp/cc-memory/save-memories.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.00038 | $0.02465 |
| Opus 5 | $0.00019 | $0.01233 |
| Sonnet 5 | $0.00008 | $0.00493 |
| Haiku 4.5 | $0.00004 | $0.00247 |
Grade A, and why
save-memories scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured today.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 201 lines — stays where its author put it; the contents beside it link to each section on GitHub.
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 ofdecision,result,config,bug,task,arch,noteimportance: 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.
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)
ip = Path.home() / '.claude' / 'plugins' / 'installed_plugins.json'
if ip.exists():
try:
# DELIBERATE MIRROR of cli/mem.py's marketplace-cache probe:
# installed_plugins.json[plugins][cc-memory@cc-memory][*]
# .installPath. Without this rung the skill was dead on a
# cache-only install (plugin installed from a remote marketplace,
# no dev-checkout path in extraKnownMarketplaces) -- the same
# class of gap as the v2.4.3 hardcoded legacy path.
_plugs = (json.loads(ip.read_text(encoding='utf-8-sig')) or {}).get('plugins') or {}
for _e in (_plugs.get('cc-memory@cc-memory') or []):
if isinstance(_e, dict) and _e.get('installPath'):
cand.append(_e['installPath'])
except (json.JSONDecodeError, OSError, AttributeError):
# why: a corrupt plugin cache costs one candidate, not the run
pass
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
# The state directory's NAME and its one-way migration live in core.layout
# (v2.13.0); this script used to spell the join itself and, after the rename
# to .ccm/, went on writing every memory into a memory/ database nothing else
# read. Ask the resolver, like every other surface. A package too old to have
# it is a mixed install (this skill is newer than the code), not a layout to
# guess at.
try:
from core.layout import memory_dir as _state_dir
except ImportError:
print('[error] core.layout is missing: the installed cc-memory package is older than this skill. Run /ccm-load to re-sync, then retry.')
sys.exit(0)
# Anchor before MemoryDB touches the path: MemoryDB CREATES the file and its
# parent, so run from a subdirectory this planted <subdir>/.ccm/memory.db --
# the exact stray the hooks have refused to create since v2.6.0, and because
# an existing database is a terminal rung, planting one there pinned all six
# hooks to it permanently. Falls back to cwd if the resolver is missing, which
# is only possible on installs predating it.
try:
from core.roots import project_root
project = str(Path(project_root(str(Path('.').resolve()))).resolve())
except Exception as _anchor_err:
print(f'[warn] root anchoring unavailable ({_anchor_err}); using cwd')
project = str(Path('.').resolve())
# Opt-out. This skill WRITES conversation memories, so a project the user
# opted out of must get nothing at all — the setting promises memories are
# 'neither readable nor writable through any cc-memory tool', and a skill is
# a tool. Checked on the pre-anchor cwd for the same reason every other
# surface does: anchoring is the step that can move up to an unexcluded parent.
try:
from core.modes import cli_opt_out_notice
_refusal = cli_opt_out_notice(str(Path('.').resolve()))
if _refusal:
print(f'[cc-memory] {_refusal}')
sys.exit(0)
except ImportError:
print('[warn] opt-out check unavailable; hooks still enforce it on writes')
mem_dir = _state_dir(project)
db = MemoryDB(mem_dir / 'memory.db')
pid = db.upsert_project(project)
memories = [
# {'category': 'decision', 'content': '...', 'importance': 4, 'topic': 'auth'},
#
# ADD MEMORIES HERE — see Step 2 for fields.
#
# NO BACKTICKS, NO DOLLAR SIGNS AND NO DOUBLE QUOTES IN THE TEXT YOU WRITE
# HERE. This whole body is a shell DOUBLE-quoted string, so bash expands it
# before python sees it: a backtick is command substitution, a dollar sign
# is variable expansion, and a double quote ENDS THE STRING — after which
# bash parses the rest as shell. Step 2 asks for concrete values such as
# numbers, file paths and parameter names, which is exactly the prose an
# LLM writes with markdown backticks. A memory recording a shell command
# would RUN that command in the user's project; one recording an
# environment variable assignment would expand the live value into a
# string that then lands in .ccm/MEMORY.md; and one quoting a phrase
# breaks the skill outright. Write command names and paths in plain text,
# or single quotes. (This comment spells the characters out in words for
# the same reason it is telling you not to type them — an earlier revision
# quoted that Step 2 phrase literally and made this file a bash syntax
# error, so the whole skill silently stopped running.)
# skills/ccm-load/SKILL.md carries the same rule; unlike this one its body
# is static, so this is the slot where the hazard is recurring rather
# than historical. Enforced by test_surfaces §7 over BOTH skills.
]
counts = upsert_batch(db, pid, None, memories, memory_dir=mem_dir)
print(f\"inserted={counts.get('inserted',0)} \"
f\"merged={counts.get('merged',0)} \"
f\"superseded={counts.get('superseded',0)} \"
f\"reinforced={counts.get('reinforced',0)} \"
f\"skipped={counts.get('skipped',0)}\")
"
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- today Changed · +14 lines 73e88da82f8b
- 4d ago First seen · 187 lines · 38 tokens per session scan A e901cd8108f4
save-memories is a skill published in the GitHub repository skymanbp/cc-memory (6 stars, last pushed yesterday), licensed MIT. It adds 38 tokens to every session and 2,465 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other skills, from other repositories
memory-config
Diagnose and configure MemSearch memory behavior. Use when the user asks about MemSearch configuration, plugin summarization, PROJECT.md/USER.md maintenance, memory directories, index health, provider routing, prompt files, or migration/compatibility questions.
memory-to-skill
Turn workflows from your MemSearch memory into reusable skills. Use when the user asks to make/create/extract/distill a skill from what they just did or from past work, review skill candidates, install a distilled skill, or 'turn this into a skill'. Manages MemSearch procedural-memory candidates under…
memory-recall
Search and recall relevant memories from past sessions via memsearch. Use when the user's question could benefit from historical context, past decisions, debugging notes, previous conversations, or project knowledge -- especially questions like 'what did I decide about X', 'why did we do Y', or 'have I seen this…
openviking-context-database
Use OpenViking from OpenClaw through @openviking/openclaw-plugin: long-term memory, session archives, resource and Agent Skill import, semantic recall, recall trace debugging, and externalized tool-result recovery. Prefer this skill when the user wants to use, query, debug, or operate OpenViking context from an…
evolve-lite:provenance
Analyze saved trajectories and recall audit events offline to record whether recalled guidelines influenced completed sessions.
evolve-lite:retention
Apply data-retention rules to the local evolve store — flag or delete stale and unused memories and expired sessions (dry-run by default).