Local-first
~/.ccrecall/ 全部本機 SQLite。沒有雲端、沒有 telemetry、沒有 outbound HTTP。
DEPS: SQLite (system)
SIZE: ~570 KB
NETWORK: none
第一週你們決定用 SQLite 不用 MongoDB,因為不想多裝一個服務。第二週修掉一個 ImageMagick 的坑。第三週定了檔案命名規則。
然後你開新對話——Claude 一件都不記得。
那些對話全躺在 ~/.claude/projects/ 的 JSONL 裡,只是下次開啟時沒人會去翻。ccRecall 負責翻:session 結束後萃取成結構化記憶,下次啟動自動帶回最多 5 筆。 本機 SQLite,無雲端,Apache-2.0。
npm install -g @tznthou/ccrecall
[ccRecall memory recall]
- macOS 上 PNG 轉 webp 用 cwebp -q 85,不要用 sips——sips 對中文檔名會靜默失敗,stdout 顯示成功但沒寫檔…
- Tailwind CLI 專案:改完 src/input.css 必須跑 npm run build,因為 dist/output.css 是 committed 的…
- 部署平台從版本檔偵測 runtime,.node-version 這類檔案必須 commit,且設上界避免平台挑到太新版本…
(608 memories available — use recall_query to search more)
記憶庫是長尾的。全部灌進去,開場第一件事就是吃掉你的 context window,而且大半跟今天要做的事無關。
所以分兩段供應:SessionStart 自動注入最多 5 筆、<300 tokens;剩下的留在庫裡,等 Claude 對話中判斷需要,自己呼叫 recall_query 去查。
// 2026-05 校正過一次「自動注入」的誇大;2026-07 再校一次——注入是真的,只是有預算上限。
// INDEX(daemon watches .jsonl) → DISTILL(Haiku, optional) → INJECT(SessionStart ≤300 tokens) → RECALL(MCP on-demand)
~/.ccrecall/ 全部本機 SQLite。沒有雲端、沒有 telemetry、沒有 outbound HTTP。
DEPS: SQLite (system)
SIZE: ~570 KB
NETWORK: none
原生整合 Claude Code lifecycle hooks(SessionStart / SessionEnd)+ MCP server 標準協議。
HOOKS: SessionStart + End
MCP: v1 protocol
SETUP: install-hooks
程式碼公開可審。SQLite + FTS5 + Node 簡單棧,沒有黑盒 vector DB 依賴。
LICENSE: Apache-2.0
REPO: tznthou/ccRecall
AUDIT: public
npm install / install-daemon / mcp add / install-hooks 四步做完,你拿到的是索引、啟動注入、跟手動 recall_save。記憶還不會自己長出來——那是第 5 步的事:一個可選的萃取 wrapper,session 結束後讓 Haiku 讀完整段對話,抽 0–5 筆存進庫裡,一次約 $0.001。
npm 一行裝好 ccmem 跟 ccmem-mcp。後續還有 3 步:daemon、MCP、hooks 各設一行命令,外加一步可選的萃取 wrapper。完整教學 →
CMD: npm i -g @tznthou/ccrecall
BIN: ccmem + ccmem-mcp
NEXT: 3 steps + 1 optional
daemon 透過 chokidar 盯住 ~/.claude/projects/ 的 JSONL,幾秒內偵測到新 session 並建索引;SessionEnd hook 負責確認這一步沒漏掉。真正把對話煉成記憶的是那個可選的萃取 wrapper——session 結束後 Haiku 讀完整段,抽出 0–5 筆(~$0.001/session)。v0.4.1+ 支援跨專案記憶——兩個專案共用 topic 時,高信心記憶自動跨界浮出。
HOOK: SessionEnd(確認索引)
DISTILL: Haiku via wrapper(可選)
STORE: ~/.ccrecall/ccrecall.db
INDEX: FTS5 full-text
下個 session 啟動時,SessionStart hook 自動注入最多 5 筆、300 tokens 以內。挑法分三層:先給冷記憶輪替的機會(v0.5.5 起排除近期已注入的,免得同幾筆長期霸榜),再補近期高信心的,不足才用 FTS 補齊。對話進行中,MCP recall_query / recall_context 由 Claude 自己判斷時機按需查。
HOOK: SessionStart
MCP: recall_query / recall_context / recall_save
BUDGET: ≤5 rows · ≤300 tokens
SELECT: cold-rotate → confidence → FTS
// INVARIANTS: LOCAL-FIRST · NO-CLOUD · NO-TELEMETRY · USER-OWNS-DATA
v0.3.0 的設計是兩層:機器自動抓的東西先進低信任的 session_journal,你手動 review、promote,才升到 AI 搜得到的 memories。理由聽起來很對——規則式評分會誤抓,寧願少抓不要錯抓。
0
PROMOTIONS · EVER
177
STUCK IN QUEUE
跑了兩個多月,資料給的答案是上面這兩個數字。沒有一筆被升級過。它不是閘門,是 dead-letter queue。
所以 v0.5.0 把整條砍掉——連同餵養它的 rule scorer、8 個沒有呼叫者的 endpoint、還有那張佔掉 65% 資料庫的簿記表。真正在跑的路徑其實一直是另一條:session 結束後 Haiku 萃取 → keyed memories → 下次啟動注入。
// 設計文件寫得再有道理,也不如自己的資料。閘門沒人走,就不是閘門。
常見的第一個問題是「記憶到底存成什麼」。答案分兩層:載體是一個 .db 檔,內容是純文字。抽屜不認識紙條上寫什麼,它就只是個 TEXT 欄位。
**規則**: macOS 上 PNG 轉 webp 用 cwebp -q 85,
不要用 sips。
**Why**: sips 對中文檔名的 webp 轉換會靜默失敗
——stdout 顯示成功,但目標路徑沒有檔案,
也沒有 stderr。
**How to apply**:
1. brew install webp
2. cwebp -q 85 input.png -o output.webp
// 粗體、列表、code block 都是 markdown 語法,
// 但 SQLite 完全當普通文字存。
Obsidian
每條記憶一個 .md 檔,散在資料夾裡
Notion
雲端資料庫 + block 結構
ccRecall
一個 SQLite 檔,一條記憶一個 row
代價是你不能用 Obsidian 直接打開來看。換到的是全文索引秒回、信心值跟存取次數用 SQL 直接查、備份就是複製一個檔案。
早期版本的 topic 抽取只認得拉丁詞邊界,整段中文對話會抽出零個 topic——中文使用者等於少拿了跨專案浮出跟元認知查詢這兩件事。v0.5.3 把中文納進斷詞規則(\p{Script=Han} + 32 條停用詞 + 助詞切分)。
npm install 只是第一步——daemon、MCP、hooks 還要各設一行命令才會跑起來,再加一步可選的萃取 wrapper,記憶才會自己長。
[ → 看完整 TUTORIAL ]