cc-history

cc-history

Provides local-first, cross-session memory for Claude Code, enabling semantic search across past sessions to retrieve procedures, decisions, or answers without exposing secrets.

Category
访问服务器

README

cc-history

CI License Python Code style: ruff

Local-first, cross-session memory for Claude Code, with redaction before embedding.

A knowledge layer that turns every past Claude Code session into searchable memory, so an answer, a procedure or a decision established in one session becomes retrievable from any other, without a single secret leaving your machine.


The problem

Every Claude Code session is a sealed bubble on disk: ~/.claude/projects/<project>/*.jsonl. Knowledge accumulates but stays trapped per session and per project. A procedure you established once (for example: "how to SSH into the production server") is invisible from every other session. You end up hunting through old conversations to re-find an answer you already got.

cc-history adds the retrieval layer that was missing, and changes nothing about Claude Code itself.

What it does

Session A (weeks ago):  "SSH to the server is: ssh deploy@host -i ~/.ssh/prod ..."
                              |
                              v   indexed, secrets masked, stored locally
Session B (today):      you: "connect to the server"
                        Claude calls recall() -> gets the procedure from Session A

The model gains two tools in every session and calls them on its own when you reference something established elsewhere:

  • recall(query, project?, top_k?) : semantic search across your whole history
  • recall_list_projects() : list indexed projects

No copy-paste between sessions. No "which conversation was that in". The memory follows you.

Why it is different

Most "AI memory" tools are SaaS: your transcripts, prompts and code get uploaded to a third-party server. cc-history is the opposite by design.

  • Local-first. Parsing, redaction, embeddings and the vector store all run on your machine. Nothing is uploaded. The only text that reaches an API is what a recall result re-injects into your Claude context, which is inherent to using Claude Code at all, and even that text is already redacted.
  • Security by design. Secrets are masked before they are embedded, so a secret never exists in the index (neither as document text nor as a vector).
  • Privacy by design. Default-deny allowlist, third-party data excluded, right-to-erasure with physical deletion (GDPR Article 17).
  • Zero API cost to run. Embeddings are computed locally (BGE-M3). Indexing and recall cost nothing but local compute.

Architecture

~/.claude/projects/**/*.jsonl        (source: main sessions only, sidechains excluded)
      |
      |  parser.py     JSONL transcript -> Exchange (user msg + assistant text + tool actions)
      |  redact.py     mask secrets and third-party PII BEFORE embedding
      |  embeddings.py BGE-M3, 1024-dim, normalized, local (MPS or CPU)
      v
   Chroma collection `claude_code_history`   (dedicated store under ~/.cc-history)
      |
      |  store.py      read-only recall core (re-scans every returned doc, fail-closed)
      v
   cc-history-recall (CLI)   +   cc-history-mcp (MCP server, exposed to every session)

Install

Requires Python 3.10+. Install straight from GitHub:

# full tool (embeddings + MCP server); pulls in torch via sentence-transformers
pip install "cc-history[all] @ git+https://github.com/Straska7/cc-history.git"

# or just the redaction library (pure Python, no torch)
pip install "git+https://github.com/Straska7/cc-history.git"

Or from a clone (for development):

git clone https://github.com/Straska7/cc-history.git && cd cc-history
uv venv && uv pip install -e ".[all,dev]"

Not on PyPI yet. Once published, pip install "cc-history[all]" will work directly.

Quickstart

# 1. Choose what to index (default-deny). List your Claude Code projects:
ls ~/.claude/projects
# then copy the example config and set `policy: allow` on the ones you want:
mkdir -p ~/.cc-history
cp config/cc_history.example.yaml ~/.cc-history/config.yaml
$EDITOR ~/.cc-history/config.yaml

# 2. Index (incremental). CPU device keeps the GPU free for other workloads.
CC_HISTORY_EMBEDDING_DEVICE=cpu cc-history-ingest
cc-history-ingest --dry-run     # show the plan, write nothing
cc-history-ingest --rebuild     # from scratch

# 3. Recall from the CLI
cc-history-recall "how do I connect to the server over ssh"
cc-history-recall --list-projects
cc-history-recall --audit       # zero-leak self-check

Use it from every Claude Code session (MCP)

Register the MCP server once, at user scope:

claude mcp add cc-history -s user -e CC_HISTORY_EMBEDDING_DEVICE=cpu -- \
  cc-history-mcp

claude mcp get cc-history       # verify
claude mcp remove cc-history -s user

From then on, every new session has recall and recall_list_projects. The server is read-only, lazy-loads the model (no RAM cost until the first recall), and wraps every result in an anti-injection envelope with provenance.

Security and privacy by design

This is the part that separates cc-history from a weekend script. The threat model is explicit: because recall re-injects stored text into the model context, which transits to the API, anything stored is potentially exfiltrated. Therefore nothing sensitive is ever stored.

Redaction before embedding

Detection and masking happen in redact.py before a single character is embedded. Placeholders are typed ([REDACTED:<type>]) so audits can tell what was caught.

Secrets and credentials masked (16 classes):

Category Types
Private keys PEM private keys, SSH key material
Cloud / provider keys AWS access key IDs, GCP API keys, Anthropic API keys, OpenAI API keys
VCS tokens GitHub tokens, GitLab tokens
Chat / bot tokens Slack tokens, Telegram bot tokens
Auth material JWTs, Bearer tokens, Authorization headers
Inline secrets export FOO=... env secrets, passwords, passwords in URLs

Third-party PII masked (4 classes):

Type Approach (tuned for a code-heavy corpus)
Email Regex + allowlist for the operator's own addresses (CC_HISTORY_OWN_EMAILS)
Phone Two formats (international, national) plus a digit-count validator, so CVE IDs, dates, versions and ports never qualify
@handle Prose-context only, with a blocklist of Python decorators and framework names, an allowlist of your own bots, and exclusion of function calls, npm scopes and attribute access
Name Only in a labeled header position (Cc: / Contact:), with an allowlist for the operator

Defense in depth: the recall path re-scans every returned document through the redactor before it leaves the store, and fails closed on any error, so even a stale or malformed index entry cannot leak.

Governance and erasure

  • Default-deny allowlist: a project is invisible until explicitly allowed.
  • Third-party exclusion: projects containing other people's regulated data are deny and never indexed.
  • Right to erasure (GDPR Article 17): --purge-session and --purge-project perform physical deletion with a store VACUUM and removal of backups, not a soft delete.
  • Auditability: --audit re-scans the entire index for any residual leak.

See SECURITY.md for the full threat model.

Keep it fresh (automation)

Two complementary refresh paths, both local and incremental:

  • On session end: a Claude Code SessionEnd hook that runs cc-history-ingest --quiet, so a finished session enters memory within seconds.
  • Nightly safety net: a cron job (or launchd/systemd timer) running the same command once a day.

Example SessionEnd hook in ~/.claude/settings.json:

{
  "hooks": {
    "SessionEnd": [
      { "type": "command",
        "command": "CC_HISTORY_EMBEDDING_DEVICE=cpu cc-history-ingest --quiet >/dev/null 2>&1 || true",
        "async": true }
    ]
  }
}

Quality and evaluation

cc-history-eval measures retrieval quality objectively against a fixed query set (paraphrases plus off-topic negatives): recall@K, MRR, and negative precision. The bundled cases are placeholders; point them at your own corpus.

On the author's own history (496 chunks) the same harness scored recall@5 = 95%, MRR = 0.887, with all off-topic negatives below the noise threshold. That evaluation is also the decision gate for adding a lexical (BM25) hybrid: it is deliberately not added, because dense retrieval already clears the bar.

Redaction is covered by unit tests including adversarial and anti-false-positive cases (Python decorators, npm scopes, CVE IDs, dates, versions, ports, UUIDs).

Limitations (honest)

  • Single machine, single user. There is no team sync, no multi-user auth, no RBAC. This indexes one developer's local history.
  • Names in free-running prose are not redacted. Masking arbitrary names in sentences requires NER, not regex. Labeled names (Cc:, Contact:) and prose @handles are covered; a bare "I spoke with Marie" is not. Precision is favored over recall here on purpose.
  • Tuned for a code-heavy corpus. The PII heuristics trade recall for precision to avoid masking code. A prose-heavy corpus would want different tuning.
  • Assumes the Claude Code on-disk transcript format (~/.claude/projects/**/*.jsonl).

Configuration reference

Everything lives under ~/.cc-history, each piece overridable by an env var:

Variable Default Purpose
CC_HISTORY_HOME ~/.cc-history base directory
CC_HISTORY_CHROMA_PATH <home>/chroma vector store
CC_HISTORY_STATE <home>/state/ingest_state.json incremental-ingest state
CC_HISTORY_CONFIG <home>/config.yaml allowlist config
CLAUDE_PROJECTS_DIR ~/.claude/projects source transcripts
CC_HISTORY_EMBEDDING_DEVICE auto cpu, mps, cuda, or auto
CC_HISTORY_EMBEDDING_MODEL BAAI/bge-m3 embedding model id
CC_HISTORY_OWN_EMAILS (empty) comma-separated own addresses to keep readable
CC_HISTORY_OWN_NAMES (empty) comma-separated own names to keep readable
CC_HISTORY_OWN_HANDLES (empty) comma-separated own @handles to keep readable

Layout

cc_history/
  parser.py        JSONL -> Exchange -> prepared chunks
  redact.py        secret and PII detection and masking (the security barrier)
  store.py         read-only recall core (re-scan, fail-closed)
  embeddings.py    local BGE-M3 wrapper
  mcp_server.py    MCP server exposing recall to every session
  config.py        allowlist loader
  paths.py         central paths and constants
  ingest.py        incremental indexer, purge, backup (cc-history-ingest)
  recall.py        CLI recall, list, audit (cc-history-recall)
  eval.py          retrieval evaluation (cc-history-eval)
config/cc_history.example.yaml   the allowlist template
tests/             redaction and parser tests

License

Apache-2.0. See LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选