cc-mem

cc-mem is a command for Claude Code from skymanbp/cc-memory. It costs 49 tokens per session (3,955 once invoked), scanned A, original, MIT.

A command-line front end for querying and managing cc-memory, a plugin that stores project memories and work state.

In plain words
What is it for?
Use it to check health and statistics, search or list memories, add a memory, inspect topics and sessions, view pending observations, and print schemas or file paths.
Why use it?
It gathers common project-memory tasks in one command instead of requiring direct database or file operations.

Command for Claude Code

Written for Claude Code: argument-hint in frontmatter.

Runs only inside its plugin — its command needs a path that Claude Code sets for a plugin’s own hooks and for nothing else. Install the plugin, not this.

Part of the cc-memory plugin — 2 skills, 1 command, 2 agents, 5 hooks shipped together

Good fit Use it to check health and statistics, search or list memories, add a memory, inspect topics and sessions, view pending observations, and print schemas or file paths.

Compare 6 commands from other repositories ↓
Install

Getting it into your agent

This one installs as part of its plugin. Adding the marketplace and installing the plugin brings it with everything else the plugin ships.

Claude Code
/plugin marketplace add skymanbp/cc-memory
Claude Code
/plugin install cc-memory

Made for: Claude Code.

Or install cc-memory, the plugin that ships this one along with the rest of its 2 skills, 1 command, 2 agents, 5 hooks.

Wrote 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.

agentmods badge for cc-mem

README.md
[![agentmods](https://agentmods.dev/badge/commands/skymanbp/cc-memory/cc-mem/github.svg)](https://agentmods.dev/commands/skymanbp/cc-memory/cc-mem)
Your own site
<a href="https://agentmods.dev/commands/skymanbp/cc-memory/cc-mem"><img src="https://agentmods.dev/badge/commands/skymanbp/cc-memory/cc-mem/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for cc-mem

Your own site · 80×15
<a href="https://agentmods.dev/commands/skymanbp/cc-memory/cc-mem"><img src="https://agentmods.dev/badge/commands/skymanbp/cc-memory/cc-mem.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 49 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 3,955 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

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.

ModelPer sessionOnce invoked
Fable 5.1 $0.00049 $0.03955
Opus 5.5 $0.00020 $0.01582
Sonnet 5.5 $0.00010 $0.00791
Haiku 4.5 $0.00005 $0.00396

Measured 3d ago against content hash 5e023bf001e3, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade A, and why

cc-mem 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 3d ago.

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.

commands/cc-mem.md · 136 lines

How it starts

The opening of the file, as written. The whole thing — 136 lines — stays where its author put it; the contents beside it link to each section on GitHub.

/cc-mem — cc-memory CLI front-end

Run cc-memory CLI commands against the current project. The wrapper resolves --project . for you.

Subcommands

Every subcommand cc_memory/cli/mem.py defines is listed here, and tests/smoke_test.py fails if one is missing — an undocumented subcommand is one nobody uses, and sql's read-only guard is a security fix that only helps someone who knows the command exists.

Subcommand Effect
stats Database statistics + supersede-chain count
status Full health check (hooks, DB, API key, PROGRESS state, consolidation: last run, backlog and which LLM stages ran — v2.16.0)
search <q> Search active memories. FTS5 ranked by bm25, with a LIKE substring fallback whenever the index answers empty. CJK and Latin do not behave identically, and the difference is the tokenizer's, not a bug: the index is built with tokenize='trigram', which segments Chinese / Japanese / Korean but has a 3-character floor, so a 1- or 2-character CJK query (超时) is answered by the substring fallback rather than by the index — same rows, no ranking. Latin text tokenises into words, so a multi-word query matches non-contiguously (deploy rotated finds "the deploy key is rotated monthly"), which the substring fallback cannot do. A query that strips to empty returns nothing — list is the surface that means "show me everything"
list [category] [--limit N] [--sessions N] List memories (filter by decision/result/bug/...). --limit caps the rows (default 20); --sessions scopes to memories from the N most recent sessions (default 5) plus every session-less manual save
add <category> "<text>" [--importance 1-5] [--tags a,b] [--topic T] Add one memory through the anti-patch writer. Defaults: importance 3, tags manual (--tags replaces it, comma-separated), no topic
topics Show topic summaries
keywords Top project vocabulary by frequency
sessions Compaction history with archive paths
observations [--limit N] Raw PostToolUse rows still awaiting extraction (default 30)
schema Print the live SQLite schema (tables, indexes, migrations)
paths [--json] Print the resolved project artifact paths — database, PROGRESS.md, PLAN.md, MEMORY.md — each with an exists/absent verdict. Read-only: an absent artifact is an answer, not an error. Exists because status reports counts with no locations, and hunting for the DB with an rglob found another project's file first
sql "<SELECT ...>" [--json|--full] Run a read-only query. Write statements are refused — only plain SELECT, WITH … SELECT, EXPLAIN and read-only PRAGMA run, and the PRAGMA name(value) setter form is refused too (an =-only test used to let it through). The default table truncates cells at 60 chars; --full prints untruncated column: value blocks, and --json emits pure-ASCII JSON (\uXXXX escapes), which no capturing shell's decode codec can garble — use it whenever CJK text comes back as �
progress Force-regenerate .ccm/PROGRESS.md from DB and print it
supersedes <id> Walk the supersede chain for a memory ID (anti-patch history)
adopt-stray <path> [--dry-run|--yes] Merge ONE stray database below this project into it — the remedy status names on each [WARN] Separate database below this project row. A dry run unless --yes. With --yes the stray's whole state directory is first MOVED (never deleted) to .ccm/.adopted/<date>/<relative path>/, then every table is imported with a provenance row in adopted_rows: memories active and archived (re-numbered, supersede links re-mapped; an active exact duplicate of a project row is imported archived and linked to it), sessions (archive paths re-pointed), summaries, topics by name, keywords summed, directives by slug, observations only where retention keeps them. Re-running is a no-op; a run cut off after the move resumes. Refuses anything not strictly below the project root, the project's own database, a .ccm-root-pinned directory and a link (exit 1); a stray in use is reported pending with nothing moved (exit 3)
archive <id>... [--supersedes ID] Retire memories found to be WRONG: is_active=0, recoverable, never DELETE. The supported exit from "this stored fact is false" — sql is read-only and add reconciles only when the new text scores similar enough to the old. --supersedes records which memory replaced them, keeping the chain walkable. Refuses ids from another project (memories.id is global to the DB file)
consolidate [--deep] [--no-llm] Run the full LLM-backed consolidation pipeline, then stamp the cadence marker (so the Stop hook's backpressure probe doesn't re-run what you just ran). --deep first loops the semantic-dedup judge until a round confirms nothing new — the way to pay a months-old backlog down in one sitting; already-refused groups are never re-judged within the run
cleanup Lightweight no-LLM cleanup + MEMORY.md regen
summary Latest session summary (request/done/next_steps)
mode [name] Show/set project mode (code/research/writing)
announce [full|batch|off] Show/set what the hooks tell YOU they did (v2.17.0): one line per act in the transcript — ccm ▸ 注入(inject) … at session start, 召回(recall) when a prompt pulled memories, 提炼(extract) / 整理(consolidate) / 存档(save) when a background run or a compaction finished, 计划捕获 / 计划同步 for the plan anchor, 失败(error) when a hook swallowed a failure. full (default) shows every line, batch drops the per-prompt recall line, off shows none. The lines are systemMessages: shown to you, never sent to the model. Per project, like mode
serve [--port N] [--no-open] Launch the browser-based web viewer (stdlib http.server; port 9377 by default). --no-open skips opening a browser tab
dashboard Launch the Tkinter GUI dashboard for this project
plan-status Live-plan counters + freshness summary (no LLM)
plan-show Regenerate + print .ccm/PLAN.md
plan-set --raw '<text>' Capture a raw plan, mark needs_refine=1
plan-set --raw-file FILE Same, but read raw from a file (UTF-8, a BOM tolerated; any other encoding is refused with a one-line remedy)
plan-set --from-refiner Read structured JSON from stdin (refiner output; a leading BOM, as PowerShell 5.1's > writes, is stripped)
plan-check Record a guardian check you have just run (resets the drift counters) — guardian FIRST, then this
plan-replan Re-arm needs_refine on the current raw
plan-clear Drop the active plan + delete PLAN.md. Archived to .ccm/.plan_history/ first; --reason "<why>" is required when unfinished steps exist (refuses and exits 1 otherwise — v2.4.0 carryover gate)
directive-list [--status active|blocked|done|superseded|dropped|all] [--json|--full] Standing user directives, most-repeated first. A directive is a unit of user INTENT and outlives every plan; a plan step is a unit of execution and dies with its plan. Default filter is active; blocked rows show as [b]. --full lifts the per-field truncation, --json emits full rows as pure-ASCII JSON
directive-add <slug> [--quote "..."] [--demand "..."] [--kind standing|feature|process|oneoff|constraint] [--times N] Record a directive. Re-adding the same slug bumps times_stated on the ONE row rather than creating a second — repetition is the importance signal a plan cannot express. --times sets the count outright, for backfilling from a transcript audit. Reference plan steps by TITLE, never by number — step ids are re-assigned on every replacement, and the command warns when the text contains step #N / 步骤 N
directive-edit <slug> [--demand ...] [--quote ...] [--kind ...] [--status active|blocked] Correct a directive's record without bumping its count — an edit is maintenance, not a re-statement, and directive-list sorts by the count. Never creates (exits 1 on an unknown slug). --status blocked parks a directive that is waiting on the user — idle enforcement skips it — and --status active un-parks it; closure stays with directive-close, whose evidence gate this door must not bypass
directive-close <slug> --evidence "<checkable>" [--status done|superseded|dropped] Close a directive. --evidence is mandatory and refuses an empty value (exits 1): a commit sha, file:line, or a gate name. A directive closed on an assertion is the exact failure the ledger exists to prevent
inject-show [--templates] Show exactly what the last SessionStart injected (ground truth); --templates lists every Claude-visible text template in core/prompts.py with its size (v2.16.0)
inject-usage [--window N] [--judge] Deterministic signals, each naming the window it was measured over — a count over an unstated window reads as evidence of absence and is not. Counts Read-tool observations targeting PROGRESS.md / MEMORY.md across the last --window observation rows (default 200; widen it when a long session may have buried the Read past them), and reports whether the handoff ack was stated — the sentence SessionStart's forced reminder demands, matched through the same constant that emits it (core.progress.ACK_TEMPLATE), in the transcript of the session that received the last injection. The ack is tri-state: yes / no / unmeasured, and unmeasured (no injection recorded, no session id in the manifest, no transcript on disk) is never rendered as no. Quoting the reminder is not stating the ack, and neither is a tool argument that contains it. Per-memory #id matching is deliberately not done — it is feasible, since the timeline layer renders #<id> for every entry past the fifth, but it would need the ids that layer actually spelled rather than the whole manifest, or it measures the injection's shape and reports it as Claude's behaviour. --judge adds layer 2, off by default: one LLM call that reads Claude's own replies from that session and judges, per delivered memory, whether it was used / unused / unknown. Layer 1 above is deterministic, free and always runs; layer 2 costs an API call, which is why it is asked for rather than assumed. unknown — no credential, a refused call, an unparsable answer, an id the judge skipped — is never printed as unused: an outage of ours is not evidence about Claude
encoding-check [--apply] Scan for U+FFFD corruption (read-only; --apply quarantines)

Read the full file on GitHub · 136 lines

Changes

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.

  1. 3d ago Changed · +2 lines 5e023bf001e3
  2. 14d ago Changed d44f96a4ef8f
  3. 22d ago Changed 976daae765f1
  4. 1mo ago Changed 43ff54599799
  5. 1mo ago Changed 9c77b7b671f9
  6. 1mo ago First seen · 134 lines · 49 tokens per session scan A 7b7926a90d23

Subscribe to this mod's changes

cc-mem is a command published in the GitHub repository skymanbp/cc-memory (9 stars, last pushed 2d ago), licensed MIT. It adds 49 tokens to every session and 3,955 once invoked, about $0.0002 per session on Opus 5.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.