记忆文件维护 · 瘦身 · 备份
一、适用场景
- 工作区
MEMORY.md接近 3000 字符注入上限,需要拆分 - 用户级
~/.workbuddy/MEMORY.md接近 4000 字符写入限额,需要瘦身 - 用户明确要求「把记忆压一压 / 整理一下 / 备份一下」
- 换机、换账户前要留存记忆快照
不适用于:单纯读取记忆内容、新增一条偏好(直接 Edit 即可)。
也不适用于:技能包的迁移与双轨同步(那属于技能开发流程的职责,与记忆文件无关,勿混用本条流程)。
二、先分清对象:三层记忆
| 层 | 位置 | 能否分卷 | 限额(硬线) | ★达标区间(收敛带) |
|---|---|---|---|---|
| 云档案 | ~/.workbuddy/memory/<UUID>_memory.md |
— | ❌ 只读,禁止本地改写(服务端管理,下次会话覆盖) | — |
| 用户级 | ~/.workbuddy/MEMORY.md |
❌ 不能(只注入这一个文件) | 4000(写入限额) | 3600 ~ 4000 |
| 工作区 | <工作区>\.workbuddy\memory\ |
✅ 能(主索引 + 分卷) | 主文件 3000(注入上限) | 2700 ~ 3000 |
动手前先确认改的是哪一层 —— 用户说「记忆」时可能指任意一层。
★ 收敛带规则(2026-10-12 定,压到就停)
达标区间 = 目标值 ×(1 ± 10%),但上界仍以硬线为准 —— ±10% 不得用来放宽上限。
| 落在哪 | 判定 | 动作 |
|---|---|---|
| 带内(如 3600~4000) | ✅ 达标 | 立即收工,不再为贴近硬线迭代 |
| 带下界以下(如 <3600) | ⚠️ 压过头 | 同样停手,如实报告「删多了 X 字」,不倒回去补写 |
| 硬线以上(如 >4000) | ❌ 超限 | 必须继续压,这是唯一需要再动手的情况 |
> 反例(本条要治的病):把目标写成「压到 3950」,实测 4144 → 4008 → 4006 → 3987,
> 迭代 4 版才罢手 —— 前两版还都超硬线,等于白跑两轮。
>
> 按收敛带该怎么做:落在 3600~4000 之间任意位置即达标。也就是说某一版若落在 3850,
> 当场收工,不必为了「更接近硬线」再压到 3987。多轮微调抠出的几十字,
> 远不如少一轮返工划算 —— 这是本条唯一要传达的意思。
三、两条路线(关键:不可混用)
路线 A:工作区 → 「主索引 + 主题分卷」(首选,无损)
注入只带 MEMORY.md 一个文件,但同目录其它文件不会被删,可被按需 Read。所以:
- 主
MEMORY.md只留:一页速览表 + 最常查的若干条 + 分卷导航(≤3000 字符) - 大块内容按主题拆到
MEMORY-01-<主题>.md/MEMORY-02-<主题>.md…(一套 3~4 卷) - 主文件顶部写明每个分卷的文件名与内容范围
- 内容零丢失,不压缩
① 长条目下沉(先补分卷、再删索引)
主索引里的长条目(>400 字符)不做压缩,而是整条搬进分卷,索引只留一行指针:
| 源条目的性质 | 搬到哪 | 判据 |
|---|---|---|
| 流程 / 编号谱 / 包与发布现状 | 03 版本历史与待办 |
「随版本演进的记档」 |
| 规则 / 口径 / 踩坑 / 对齐版式 | 04 踩坑与教训 |
「跨版本稳定的规则」 |
| 骨架 / 硬规则清单 | 02 |
「报告结构本身」 |
| 流水线怎么跑 | 01 |
「包状态与流水线」 |
搬之前先查目标分卷是否已有承接位 —— 已有则直接删源(只留指针);没有则先补写并回读校验,再删索引(顺序不可倒,否则出现「内容只存在于被删行」的空窗)。
② 索引目标形态(配额参考)
一条一行指针,每条 ≤60 字符,格式:★ 规则名:一句话判据 → 分卷节号(如 04 §五)
| 段 | 目标字符 | 说明 |
|---|---|---|
| 头 + 分卷导航 | ~140 | 4 卷压成 2 行 |
| 一页速览 | ~450 | 7~9 行,每行 ≤70 |
| 最常查的 N 条 | ~700 | 16 条 × ~45 |
| 合计 | ~1300 | 距 3000 留 1700 余量(余量可用于放回常用长条,不必强压) |
路线 B:用户级 → 瘦身(不可分卷,只能压)
~/.workbuddy/MEMORY.md 是唯一被注入的文件,分卷无用 → 只能瘦身:
- 先出只读分级清单:逐条标
保留 / 合并 / 删除 / 压缩+ 现字符 + 理由 + 目标字符 - 找「已固化到技能」的内容 → 可无损删除(改为「→ 见技能
xxx」一行指向) - 合并重复项、删取证细节、留结论
- 用户确认后执行(默认推 A 档,另备 B 保守 / C 激进)
例外:若内容属于某技能领域(判重、文档生成等)且技能已覆盖 → 删记忆条目,改为指向技能。先核实技能是否真覆盖(grep 关键词),不可凭印象。
四、★ 备份铁律(统一目录,便于回看)
结构性改动前必须先备份(拆分 / 瘦身 / 重写 / 批量删条)。追加式日志 YYYY-MM-DD.md 属常规写入,不必逐次备份 —— 它设计上只增不改,风险与 MEMORY.md 不同量级。
统一归档目录
<备份根目录>\MEMORY-备份\
├─ README-备份索引.md ← 每次追加一行(见下)
├─ 20260930-用户级\
│ └─ MEMORY.md
└─ 20260930-项目-dip-report-deliverable\
├─ MEMORY.md
└─ MEMORY-01-*.md …
| 规则 | 内容 |
|---|---|
| 备份范围 | 只备份策划式记忆文件:MEMORY.md + 全部分卷;追加式日志不在此列 |
| 每次一个子目录 | <YYYYMMDD>-<范围>;范围 = 用户级 / 项目-<项目名> |
| 保留原文件名 | 用户级 MEMORY.md;项目级 MEMORY.md + 全部分卷 |
| 双份 | ① 本机原地 .bak_<YYYYMMDD-HHMM>(快速回滚,与源同目录)② D 盘统一目录(长期归档,跨机/跨账户可查) |
| 校验 | 复制后 sha256 比对一致 才算完成;不一致则报告失败 |
| 索引 | 在 README-备份索引.md 追加一行:日期 \| 范围 \| 字符数 \| 条数 \| 触发原因 \| 来源路径 |
| - 索引行必须写在表内:追加行应加在表格末行之后;写到「备注」区会破坏表块结构(2026-10-01 那行曾误落备注后,2026-10-04 才上移修正)。 |
为什么要统一目录
- 分散在各处的
.bak_时间一长就找不到 → 统一根目录后按日期排序即时间线 - 有了索引表,回看时不必逐个打开文件猜内容
- 换机/换账户时只拷一个目录就能带走全部记忆历史
已有备份的归拢
发现历史上的散落备份时,用 shutil.copy2 复制(不移动、不删除),按规范命名后放入统一目录;原备份保留原地,用户确认后再清理。
五、六步流程(固定动作)
- 盘点(只读):
len()数出字符数、按节统计条数、定位超限点 - 出清单(只读):逐条
保留 / 合并 / 删除 / 压缩+ 理由 + 目标字符;给 2~3 档方案 - 等确认:用户拍板后才动手(不要边改边问)
- 备份:按第四节双份备份 + sha256 校验 + 索引登记
- 改写:路线 A 拆卷(先补分卷 → 回读校验 → 再删索引)/ 路线 B 瘦身;一次成型,不做半成品。索引含表格时用 Python heredoc 脚本直写(不走 Write 工具),写完回读
|计数
> 顺序铁律的理由:先删索引后补分卷,中间态会出现「某条内容既不在索引、也不在分卷」的空窗 —— 此时若会话中断即永久丢失。
★每写完一版立刻 len() 验数:落进 §二收敛带(目标 ±10%)就收工,不要为贴近硬线再压一轮。仅当仍超硬线时才继续。
6. 校验 + 回填:跑 scripts/verify_memory.py(会直接给出 达标 / 压过头 / 超限 判定);回填清单与日志的「已改记录」
六、校验三件套 + 硬线 + 收敛带
python scripts/verify_memory.py <记忆文件路径> --limit 4000 --tolerance 10
| 项 | 判据 |
|---|---|
| 字符数 | 三档:达标(落在目标 ±10% 内,且不超硬线)/压过头(低于下界,停手并如实报告)/超限(超硬线,唯一需要继续压的情况)。默认 --tolerance 10 即 ±10% |
| 竖线 | 逐个打印含 \| 的行与数量 —— 确认没有被静默吞掉 |
| 表块 | 转义感知:先把 \\\| 替换成占位符再数列数,否则有意转义的竖线会被误报为列数不一致 |
| 锚点 | 抽查关键条目仍在(人名、ID、路径、工具名等) |
> 收敛带 = --limit 值 ×(1 ± --tolerance%)。上界不超过 --limit —— 容差只能放宽下界,不能放宽上限。
> 例:--limit 4000 --tolerance 10 → 达标区间 3600 ~ 4000;--limit 3000 → 2700 ~ 3000。
写含表格的 md 后,必须做表块列数校验 —— Write/Edit 偶发吞 |,一旦发生是静默的(不报错、内容错位)。
七、避坑清单(实测教训)
| 坑 | 真相 |
|---|---|
| 凭估算压缩,总偏大 | 一轮:计划「压到 3950」实测 4144 → 4008 → 4006 → 3987(迭代 4 版);二轮:预估省 238、实测仅省 165,两次分别低估 95 与 31 字符。对策:每写完一版立即 len();★且落进 §二收敛带(±10%)就收工 —— 那轮最后 4006→3987 只为 19 字又跑一版,按新规则本可省掉 |
| 贪心贴硬线(★2026-10-12 立) | 把目标写成「3950」这种贴着硬线的数,注定要多轮微调。目标就写硬线值本身,落在 ±10% 带内即达标。压到带下界以下也算压过头,停手并如实报「删多了 X 字」,不要倒回去补写 |
| 「省 X 再加 Y」要算净额 | 净额 = 省 − 新增。二轮省 165、新增 144,净减只 21 → 余量从 5 仅升到 26。先腾够再写,或把新条目本身写短(本例两轮压到 144) |
写文件用 python -c "..." |
反引号/反斜杠/$ 会被 bash 静默吃掉 → 改文件一律用 Write/Edit |
| Write 吞竖线 | 含 \| 的字符串可能落盘成无分隔版 → 写完 print 回读校验 |
| 校验脚本没做转义感知 | \| 是有意转义,会被算成 2 个竖线 → 误报列数不一致。先替换再计数 |
| 动手前没出清单 | 记忆是红线载体,改错会长期影响 → 先只读清单 + 等确认 |
直接改 memory/<UUID>_memory.md |
服务端管理,下次会话被覆盖 → 只读它,要留内容就并入用户级 MEMORY.md |
| 按「感觉重要」删条目 | 删除判据只能是「是否已被技能/其他文件完整覆盖」,须 grep 核实 |
| 索引改写必超预算 | 2026-10-04 实测(当时目标 1500):迭代 6 版(1918 → 1779 → 1655 → 1591 → 1534 → 1474)。写索引时按 ~1300 下笔、留足余量。★2026-10-06 起目标改为 3000,余量大幅放宽,此条仅作「改写易超」的提醒 |
| 备份目录先命名后拷贝 | 先建 <YYYYMMDD>-<范围> 规范目录再 copytree,别先拷成随手名再改(本次先写成「主索引瘦身前」,事后只好用 shutil.move 改名补正) |
八、附带脚本
| 脚本 | 用途 |
|---|---|
scripts/verify_memory.py |
字符数 + 限额判定 + 竖线逐处 + 转义感知表块校验 + 锚点抽查 |
用法:
python scripts/verify_memory.py "~/.workbuddy/MEMORY.md" --limit 4000
python scripts/verify_memory.py "<工作区>/.workbuddy/memory/MEMORY.md" --limit 3000 --anchors <你关心的关键词>,UUID,4000