18477514055/dsh-ledger-memory ↗★ 1
dsh-ledger-memory
台账记忆(Ledger Memory):为 DSH 提供工程化的项目记忆 —— 台账的检测/注入/归档/Git 配合,活动日志(L0–L4),三层上下文压缩与逐字胶囊落盘,两种压缩模式(正常推进 / 反复追究),把会话锁定到某个项目目录,以及跨会话的交接单闭环。可回溯、可追查。 适合需要跨会话项目记忆、活动日志回溯及上下文压缩的项目开发者。
インストール
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:18477514055/dsh-ledger-memoryドキュメント
README 全文を読む ↗dsh-ledger-memory(台账记忆)
一个 DSH(DeepSeek Harness)宿主侧插件:让 AI 用可复现的方式,把项目里的工作记住。
它管的不是聊天记录,而是一个项目自己的记忆载体 —— 台账: 可回溯、可追查、只追加、按周归档。围绕它还有活动日志、上下文压缩与跨会话交接。
不预设任何模板 —— 台账的文件名、分几个文件、有哪些字段,全部由 AI 在初始化时 按项目类型自己决定;插件只做检测 / 注入 / 回写 / 归档 / Git 配合这些流程性工作。
它解决什么问题
| 问题 | 它怎么做 |
|---|---|
| 换个会话就"忘了这个项目干到哪" | 会话开始把活跃台账全文注入上下文;内容没变则不重复注入(防打烂 prompt 缓存) |
| AI 走完一轮,成果没落地 | 回合末把「完成了什么 / 卡在哪 / 下一步」写回活跃台账 |
| 台账越来越长,读不完 | 超阈值时把最旧的已完成条目移进 归档目录/YYYY-MM/weekN,只追加不删除 |
| 细节被上下文压缩抹掉 | 压缩之前把用户原话、报错原文、改过哪些文件落盘成一份逐字胶囊;压缩后与台账一起注回 |
| 新会话接不上旧会话 | 写一份交接单,并把指针推进新会话的第一轮注入(不是等你来问) |
| 想查"谁什么时候改过这份台账" | 台账末尾自动维护一张变更登记;完整历史在只追加的活动日志里 |
| 只是一次性排查,不是项目 | ledger_note 写一份问题记录(现象 → 根因 → 结论 → 做了什么),不建台账 |
三层上下文压缩
| 层 | 触发 | 做什么 |
|---|---|---|
| ① 常态 · 增量 | 水位比上次压缩涨约 20 点 | 只压最旧一段,保留最近约 10 点不动 |
| ② 兜底 · 全量 | 水位到 70%(内核默认是 80%) | 全量压缩,但保留指向所需内容的指针:用户原话 / 报错原文 / 改过哪些文件 / 去哪重读 |
| ③ 终局 · 交接 | 你要换会话时 | 交接单让新对话无缝接上 |
围绕这三层有一条铁律:先记台账,再压缩。水位提醒发出的那一刻,插件会记住 「已经要求它写台账了」,在它写完之前不压缩 —— 否则压掉的正是这一轮唯一的那份进展。
安装
需要 Node.js ≥ 22.19。
# 走 npm
npm install dsh-ledger-memory
# 或走 DSH 自己的插件命令
dsh plugin add dsh-ledger-memory
装完重启客户端才生效 —— 内核对已加载的插件不会因文件改动自动重载。
用法
不用配置什么。打开一个项目目录开始工作,插件会:
- 发现这里还没有台账 ⇒ 注入一句提示,让 AI 来问你要不要初始化(它不会自己动手);
- 你同意后,AI 按这个项目的类型设计一套台账结构并登记;
- 之后每个会话自动加载、每轮结束自动回写、超长自动归档。
手动命令
在对话里敲 /ledger(不带参数会弹一张可点的卡片),或用子命令:
/ledger status 看状态(有没有台账、用的哪个文件、几行、Git、日志开关)
/ledger show 把当前活跃台账全文打出来
/ledger init 初始化台账(由 AI 为这个项目设计一套结构)
/ledger update 让 AI 把本次会话的进展写回台账
/ledger archive 把最旧的已完成条目移进归档目录
/ledger compact 立刻做一次全量压缩(保留指针)
/ledger light 轻量压缩
/ledger log 查活动日志
/ledger handoff 写一份交接单
/ledger mode 看/切换压缩模式(steady / surgical)
/ledger lock 把本场对话锁到某个项目目录(总工作区里用)
对话建在总工作区时:锁定到子项目
有时对话是建在装着多个项目的总工作区上的。那时插件无从判断"这次说的是哪个项目", 默认就都落在当前目录。解决办法是锁:
/ledger lock 20-DSH插件/04-其余插件/10.项目台账
锁定后,本场对话的所有工具调用都落在那个目录上,不必每次再指定。
/ledger lock 不带参数看当前状态,/ledger lock off 解锁。
会话第一轮弹的那张卡片里也有这个选项。
★ 这个锁只存在内存里:不建注册表、不在你的目录里留任何标记、一个文件都不写, 换一场对话就回到默认。它只影响"这次往哪儿记",不改你磁盘上的任何东西。
★ 若当前目录自己就有台账,仍以当前目录为准 —— 锁只接管"没有台账"的目录。
设置面板
设置 → 项目台账(台账 / 压缩 / 日志),可调十三项:压缩模式、回合末卡片开关、 高保真压缩水位、增量压缩的涨幅与保留量、活动日志五档开关、活跃台账行数上限、 变更登记条数、水位提醒档位等。
一条要知道的语义:
mode/maxActiveLines/changeRegisterMax/logLevels以每个项目自己清单里的值为准。面板里这几项是新项目初始化时写进去的默认值。
两个压缩模式
压缩方式可以按项目选。默认是「正常推进」,两者共用同一套压缩,区别只在压缩前后多做或少做什么:
正常推进(steady,默认) | 反复追究(surgical) | |
|---|---|---|
| 压缩时怎么切 | 按位置:只压最旧一段,更早的一刀切 | 按内容分流,再压 |
| 谁做判断 | 不用判断(省一次模型输出) | AI 做一次分流 |
| 适合 | 一路向前干活 | 要反复回看约束与假设的活 |
「反复追究」怎么工作:水位到点时会先让 AI 调 ledger_triage 把这一段分成三个桶 ——
- 留(
keep):下一轮不知道就会做错的东西(当前状态、未验证的假设、你定过的约束)。压缩后逐字注回。 - 落(
stash):以后可能要查、但不该占上下文的(判断与理由、走不通的路、关键文件位置)。 写进项目的_stash/,永不注入,需要时自己 grep。 - 丢(
drop):已被取代的,只进日志。
keep 有条数上限——留得太多等于没压,超了会按 AI 给的顺序截断并如实报出截掉几条。
切换:设置面板里选,或 /ledger mode steady / /ledger mode surgical(只影响当前项目)。
十四个工具
AI 在对话里调用,你也可以让它调用:
| 工具 | 作用 |
|---|---|
ledger_status | 报告这个项目的台账状态(只读) |
ledger_read | 读台账 / 决策记录 / 归档 |
ledger_write | 写活跃台账或决策记录 |
ledger_init | 登记台账结构(四条硬约束:一个活跃台账 / 一份独立决策记录 / 一个只追加归档目录 / 行数上限) |
ledger_archive | 把旧条目移进只追加的归档 |
ledger_conform | 检查一个既有项目的台账是否符合预期,能修的只做加法 |
ledger_note | 写一份问题记录(非项目场景,有终点的那种) |
ledger_log | 查活动日志(五档,从不注入上下文) |
ledger_log_write | 追加一条回合小结 |
ledger_handoff | 写交接单,供下一个会话接手 |
ledger_triage | 把阶段性产出分成「留 / 落 / 丢」三个桶(「反复追究」模式用) |
ledger_lock | 把本场对话锁到某个项目目录(只存内存,不写任何文件) |
ledger_compact | 请求一次高保真压缩 |
ledger_checkpoint | 把这一刻的选择交给用户(记台账 / 记+压缩 / 记+交接 / 跳过) |
活动日志(五档)
挂在你为项目登记的日志目录下,只追加、永不改写,且从不注入上下文(按需查):
| 档 | 内容 |
|---|---|
| L0 | 台账变更的里程碑 |
| L1 | 回合小结(带会话编号) |
| L2 | 文件流向 |
| L3 | 工具调用流水(默认关) |
| L4 | 逐字存档你说过的每一句话(带会话编号与时间) |
采集类档位只认会话的工作目录,不会去猜子项目。 在一个装着多个项目的目录里开会话时,采集类档位写不出东西 —— 这是刻意的。
依赖与许可
- 零运行时依赖(
dependencies为空) - 唯一 peer 依赖:
@deepseek-ai/cordis - 许可:MIT
自检
仓库里带一套离线自检,不需要网络、不需要装 DSH:
npm test
已知边界
- 注入走
agent/pre-step(可替换本轮消息),不是systemPrompt.context。 - 改代码后必须重启客户端,内核对已加载插件不会热重载。
- 采集类日志档位在"容器工作区"(装着多个项目的目录)里写不出东西。
- 压缩服务只能经
agentPresets.serviceFor(agent, "compaction")取到,ctx.get("compaction")恒为undefined。