持久記憶:Claude Code 如何記住事情
解析 Claude Code 檔案式持久記憶的運作方式 — 一個事實一個檔案、MEMORY.md 索引、四種記憶類型,以及讓回憶保持有用的整潔規則。
你將學到什麼
在 Claude Code 的歷史上,絕大多數時候每個 session 都是從零開始。你可以把長期規則寫進 CLAUDE.md,但 session 中學到的一切 — 你星期二做的修正、上個月發現的部署地雷 — 都會在 session 結束時煙消雲散。Fable 5 世代用每個專案一個檔案式持久記憶目錄改變了這件事。
完成後,你將了解:
- 記憶存放在哪裡,以及「一個事實一個檔案」的格式
- 四種記憶類型:
user、feedback、project、reference MEMORY.md(始終載入的記憶索引檔)如何運作- 記憶之間的 wiki 風格
[[links]]連結 - 讓記憶保持有用而非淪為雜訊的整潔規則
- 回憶(recall)如何運作(以及為什麼被回憶的記憶必須重新驗證)
- 上下文摘要(context summarization)如何取代硬性壓縮
問題所在
一個沒有記憶的 agent 會強迫你充當它的記憶。每個 session 你都要重新解釋:staging 資料庫是名字很怪的那一個、你偏好 squash merge、那個不穩定的測試早就調查過了,問題出在 CI runner 的時鐘。這是實實在在的成本,每次 session 開始都要付一次。
兩種天真的解法都行不通:
- 重新載入聊天記錄。 逐字稿非常龐大且大多是雜訊 — 工具輸出、死路、被放棄的方案。整批載入等於把上下文視窗燒在垃圾上。
- 把所有東西塞進 CLAUDE.md。 CLAUDE.md 是給長期規則用的 — 怎麼建置、要遵循什麼慣例。混入短暫的發現(「auth 重構做到一半」)會把你的規則檔變成一個會過期的雜物抽屜。
我們需要的是第三種東西:經過整理、可長期保存的知識 — 能跨 session 累積、載入成本低、錯了還能修正。
如何運作
一個記憶、一個檔案、一個事實
每個專案都有一個記憶目錄:
~/.claude/projects/<project-slug>/memory/
├── MEMORY.md ← the index (always loaded)
├── user_prefers-squash-merges.md
├── feedback_use-pnpm-not-npm.md
├── project_auth-refactor-status.md
└── reference_staging-dashboard.md
規則很嚴格:一個記憶 = 一個檔案 = 一個事實。 每個檔案帶有 YAML frontmatter:
name— 簡短的 kebab-case slugdescription— 一行摘要,回憶時用來判斷相關性metadata.type—user、feedback、project、reference其中之一
為什麼一個檔案只放一個事實?因為事實會各自獨立地改變。當 auth 重構完成時,你刪掉那個檔案就好 — 而不是在一份龐大的筆記文件裡翻找它污染到的每一句過期敘述。
四種記憶類型
| 類型 | 記錄什麼 | 範例 |
|---|---|---|
user | 使用者是誰 — 角色、專長、偏好 | 「偏好 squash merge;資深後端工程師」 |
feedback | 修正與已確認的做法,附上 Why(為什麼)與 How to apply(如何套用) | 「用 pnpm,不要用 npm — npm 會弄壞 lockfile」 |
project | 進行中的工作、目標、無法從程式碼或 git 歷史推導出的限制 | 「auth 重構暫停,等待安全審查」 |
reference | 指向外部資源的指標 — URL、儀表板、工單 | 「staging 指標在 Grafana 儀表板上」 |
feedback 類型是主力。它的內文應該回答兩個問題:為什麼(Why)這是正確做法,以及下次如何套用(How to apply)。少了這兩點的修正,只是一條 agent 在稍微不同的情境下就會用錯的規則。
注意有一種東西不是類型:「程式碼結構」。這是刻意的 — 見下方的整潔規則。
MEMORY.md:始終載入的索引
如果每個 session 都載入所有記憶檔案,就會重演聊天記錄的問題。所以系統採用你在第 5 堂課的 skills 中看過的同一套延遲載入哲學:名稱先行,內容按需載入。
MEMORY.md 就是索引 — 每個記憶一行:
- [Use pnpm, not npm](feedback_use-pnpm-not-npm.md) — npm installs corrupt the lockfile
- [Auth refactor status](project_auth-refactor-status.md) — paused pending security review
索引在每個 session 都會載入上下文。記憶的內容留在個別檔案裡;索引裡只放指標。agent 每個事實只需掃過一行,只有在相關時才拉出完整檔案。
Wiki 風格連結
記憶之間透過 slug 用 [[wiki-style]] 連結互相連接:
The lockfile issue first surfaced during the [[project_auth-refactor-status]] work.
懸空連結(dangling link)沒有關係 — 指向一個還不存在的記憶的連結,只是標記出一件之後值得寫下來的事。這是一種便宜的方式,可以留下線索而不必停下來把完整的事實寫完。
回憶是背景脈絡,不是聖旨
當記憶在 session 中被回憶起來時,它們會出現在 <system-reminder> 區塊裡 — 由 harness 注入的提示,跟工具可用性變更、模式變更用的是同一套機制。有兩個性質很重要:
- 它們是上下文,不是使用者指令。 被回憶的記憶不下命令,只提供資訊。
- 它們反映的是寫下當時的真相。 程式碼庫從那之後已經前進了。被回憶的記憶在採取行動前,必須對照當前程式碼重新驗證。
第二點正是記憶幫上忙與幫倒忙的分水嶺。一則六週前寫的「config loader 在 src/utils/」的筆記,是一條該去查證的線索,不是一個可以直接蓋上去的事實。
三層知識架構
記憶不會取代 CLAUDE.md 或 skills — 它補齊了一個堆疊:
CLAUDE.md → standing rules ("always use pnpm; run tests before commit")
Memory → accumulated experience ("we tried X on 2026-06-12; it broke Y")
Skills → procedures ("how to cut a release, step by step")
規則、經驗、程序。如果你發現自己寫的記憶讀起來像一條規則,就把它移到 CLAUDE.md。如果讀起來像一步一步的流程,那它應該是一個 skill。
摘要取代了硬性壓縮
持久記憶搭配的是長對話處理方式的改變。在舊世代(第 6 堂課),撞到上下文上限會觸發「auto-compact」(自動壓縮)。在 Fable 5 世代,當對話變長時,部分或全部上下文會被摘要;摘要加上任何尚未被摘要的上下文會帶進下一個上下文視窗,工作無縫接續。agent 會被明確告知它不需要提前收尾或在任務中途交接。
兩個配套細節補完這幅圖:
- Scratchpad 目錄(暫存目錄):每個 session 都有一個 session 專屬的 scratchpad 目錄,用於存放所有暫存檔案(而不是
/tmp)— 與專案隔離,且通常不需要權限提示就能使用。短暫的工作檔案放這裡,不要進記憶。 - 分工很乾淨:摘要保存這個 session 的脈絡;記憶保存應該活得比 session 久的東西;scratchpad 存放完全不該留下來的東西。
實作範例
這是一則貼近實際的 feedback 記憶,按照格式的本意撰寫 — 一個事實、一行方便回憶的描述,以及包含 Why 與 How to apply 的內文:
# File: ~/.claude/projects/my-shop-app/memory/feedback_use-pnpm-not-npm.md
---
name: feedback_use-pnpm-not-npm
description: Always use pnpm in this repo — npm installs corrupt pnpm-lock.yaml
metadata:
type: feedback
---
# Use pnpm, not npm
Confirmed on 2026-07-08 after a broken deploy.
## Why
The repo is a pnpm workspace. Running `npm install` writes a
package-lock.json and desyncs pnpm-lock.yaml, which broke the
CI install step (see [[project_ci-pipeline]]).
## How to apply
- All installs: `pnpm install`, never `npm install`
- Adding deps: `pnpm add <pkg>` in the relevant workspace package
- If package-lock.json ever appears, delete it and re-run `pnpm install`
以及它在 MEMORY.md 中的索引行:
- [Use pnpm, not npm](feedback_use-pnpm-not-npm.md) — npm installs corrupt pnpm-lock.yaml
注意這些細節:
- 絕對日期。 寫的是「Confirmed on 2026-07-08」,不是「昨天確認的」。相對日期會腐爛 — 三個月後再讀這個檔案時,「昨天」毫無意義。
- 懸空連結。
[[project_ci-pipeline]]可能還不存在。沒關係 — 它標記了一則值得寫的記憶。 - description 物有所值。 回憶時就是用這一行判斷相關性,所以它陳述的是事實本身,而不只是主題。
整潔規則
記憶品質靠的是維護,不是累積。四條規則:
- 更新,不要重複。 事實改變時,編輯既有檔案。兩個檔案對同一個事實各說各話,比沒有檔案更糟。
- 刪除錯誤的記憶。 一則被證明為假的記憶是負價值。移除它。
- repo 已經記錄的東西不要存。 程式碼結構、git 歷史、CLAUDE.md 裡的任何內容 — 這些以 repo 為唯一真相來源,而且永遠是最新的。與之重複的記憶注定會過期。
- 把相對日期換成絕對日期。 「上週」改成「2026-07-01」。
前後對比
| 沒有持久記憶 | 有持久記憶 |
|---|---|
| 每個 session 從零開始 | 整理過的事實按專案持久保存 |
| 你反覆重新解釋偏好與地雷 | user 與 feedback 記憶替你記著 |
| 學到的脈絡隨 session 消亡 | 一個事實一個檔案,活得比 session 久 |
| 聊天記錄是唯一紀錄(雜訊多、超龐大) | MEMORY.md 索引:每個事實一行 |
| CLAUDE.md 變成雜物抽屜 | 規則、經驗、程序 — 各自分層 |
| 撞到上下文上限就硬性壓縮 | 摘要讓工作跨視窗延續 |
關鍵洞見
記憶是整理過的知識,不是聊天記錄。
這個設計在每一個層面都做出同樣的選擇:提煉,而不是堆積。一個檔案一個事實,迫使每則記憶都是一個經過斟酌、可編輯的單位。索引加檔案的拆分,讓始終載入的成本壓到每個事實一行 — 與讓 skills 得以擴展的「名稱先行、內容按需」哲學如出一轍。整潔規則之所以存在,是因為記憶的失效模式不是遺忘 — 而是信心滿滿地記著已經不再為真的事。
這也是為什麼回憶是以「需要重新驗證的背景脈絡」的形式到來,而不是必須服從的指令。一個好的記憶系統不是讓 agent 信任它的過去,而是讓過去變得便宜好查證。
下一堂課
第 30 堂課涵蓋 Deferred Tools 與 ToolSearch(延遲載入工具與工具搜尋)— 你現在已經看過兩次的「名稱先行、定義按需」哲學(skills、記憶),如何被推廣到整個工具介面,以及為什麼這對擁有大量工具目錄的 MCP 伺服器最重要。