dsh-trilogy
Per-project memory for DeepSeek Harness: auto-creates memory/PROJECT.md, DECISIONS.md and SESSIONS.md per project, loads them into every session, and records durable outcomes by classification.
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:TodayJin/dsh-trilogy说明文档
阅读完整 README ↗使用
装好后不需要任何操作:
- 在任意项目里开一个会话 →
memory/三个文件和AGENTS.md的 boot block 被自动创建; - 项目还没被描述过时(
PROJECT.md五节全是暂无)→ 注入一条"去调研这个项目并填上"的指令, 模型会读 README / 构建与测试配置 / 入口点 / 目录结构,并真的跑一遍测试命令,然后填PROJECT.md。 填完就不再提; - 之后每个会话开始 → 三个文件自动注入上下文(内容没变则不重复注入,KV cache 友好);
- 会话干了实事却没记录 → 收尾时收到一条很短的提醒,由主模型自己判断该不该记。
初次填充(bootstrap)
模板不等于项目说明。插件把"先调研再写"这一步也自动化了 ——
scaffold 出空模板后,只要 PROJECT.md 还是空的,就注入一条 bootstrap 指令,要求:
- 读 README、构建与测试配置、入口点、目录结构;有测试命令就真的跑一遍并记录是否通过;
- 用
memory_checkpoint填PROJECT.md五节 —— 每条论断都必须来自读过的文件或跑过的命令; - 补一条真实的
SESSIONS.md记录和已定的DECISIONS.md条目。
填完后 bootstrap 自动消失(靠内容判断,不需要额外状态)。用 bootstrapWhenEmpty: false 关掉。
手写了自己标题格式的
PROJECT.md不会被判定为"空",因此不会被反复催。
输入框状态图标
对话框左下角(conversation.input.left 座位)常驻一个小指示器:
[图标] 正在记录 · 刚刚
| 阶段 | 显示 | 触发时机 |
|---|---|---|
recording | 正在记录 | memory_checkpoint 正在写文件 |
updating | 正在更新 | 长时间写入进行中 |
done | 更新完毕 | 刚写完(约 8 秒后自动回落为「已同步」) |
idle | 已同步 | 无进行中的写入 |
后面跟的是最近的同步时间(刚刚 / N 秒前 / N 分钟前 / N 小时前 / N 天前)。
悬停显示完整信息:状态、最近同步、工作区路径、写入的文件。
数据来自宿主时钟 —— 响应里带一个 now 字段,所以浏览器不需要相信自己的时钟。
客户端每 4 秒轮询一次 GET /trilogy/status;宿主不可达时保留最后一次读数。
图标用 UI primitives 的
IconLoadingOutline16/IconRefreshOutline14/IconCheckOutline14/IconDatabaseOutline16;若该模块缺少对应图标, 自动回退成一个会随状态变色的圆点。
图形设置界面
插件带一个浏览器半边,在 设置 → 项目记忆 里:
| 功能 | 说明 |
|---|---|
| 看记录 | 左栏选工作区(可按路径筛选);右栏顶部写明选中的是哪个、什么状态、最近什么时候动过 |
| 看内容 | 页签按文件的用途命名:现状 / 决策 / 日志 / 归档,右侧标出对应的文件名与字节数 |
| 清除 | 删掉该工作区的全部记忆文件(含 SESSIONS-archive.md),并撤回 AGENTS.md 里的 boot block。注册表条目保留 —— 下次在该工作区开新会话会重新创建空文件 |
| 只读查看 | 四个记忆文件在面板里都只读:写入交给会话里的 memory_checkpoint(或导入记忆包),界面里唯一能编辑的是下面的指令文件 |
| 重新读取 | 放在页签条里、紧挨 归档 左边 —— 它重新读取的正是这些页签选中的那个文件 |
| 搜索筛选 | 工作区多时按路径过滤 |
| 指令文件 | 显示 AGENTS.md 里 Memory 段的状态(已写入 / 旧版本 / 未写入 / 文件不存在)。可重写或移除这一整段 —— 只摘这一段,文件其余内容原样保留;也可以编辑整份文件,整份替换,Memory 段也在里面。注意:移除(或在整份编辑里删掉)这一段后,该工作区下一个新会话会把它写回;要永久关闭请设 writeBootBlock: false |
| 陈旧提醒 | PROJECT.md 落后于其余记忆文件超过 projectStaleDays(默认 14 天)时,在面板顶部给出横幅,并说明这期间追加了多少条日志 |
| 归档与恢复 | 归档页签逐条列出被搬走的会话记录,点「恢复这条」把它搬回活日志顶部。归档条目只读,要改就先恢复回日志,再让会话改写。归档和活日志一样最新在最上 —— 每一轮搬出去的批次都头插到归档正文最前 |
| 导出 / 导入 | 把一个工作区的 memory/ 导出成单个 JSON 记忆包,在另一台机器或另一个工作区导入。导入会覆盖同名文件,且只接受本插件导出的包(按 kind 校验) |
| 危险操作单独一行 | 「清除记忆文件」被移到最底部、与常用按钮分开,并且要连点两次(第二次是「确认清除」,旁边写明会删掉什么)才真的执行 |
工作区列表在打开设置页时从活会话回填,所以历史项目(在新功能之前建的 memory/)也会出现。
写入受限:清除、初始化、保存都是写操作,而裸 webServer 路由本身没有鉴权。保存 的
白名单按工作区解析 —— 只允许那三个记忆文件,加上该工作区自己注册的指令文件,别的一律拒绝
(面板只在指令文件上提供编辑器,但宿主这层白名单没变)。因此
整个 /trilogy 前缀被限制为本机访问(非 loopback 返回 403)。
插件完全不调用模型 —— 没有向量检索、没有 embedding、没有后台蒸馏。
PROJECT.md的初次内容由会话里的模型自己去读文件、跑测试命令后写入。
模型侧工具
| 工具 | 作用 |
|---|---|
memory_checkpoint | 按路由表分类写入。参数:sessions[] / decisions[] / project[] / notes |
memory_read | 按需读取某个记忆文件(三个文件默认已自动加载;也含 SESSIONS-archive.md) |
memory_search | 零依赖 BM25 检索,连归档一起搜 —— 注入预算之外的内容也找得回来 |
日期由插件从系统时钟盖戳,不靠模型记 —— 让模型自己读系统日期是不可靠的。
收尾兜底(nudge)
- 不额外调用模型 —— 复用当前会话里已在跑的主模型,token 开销只是一条短提醒
- 只在「这轮干了实事」且「这轮没记录任何东西」时触发
- 有冷却时间与每会话次数上限,无事发生的轮次不打扰
- 「值不值得记」由主模型判断(它上下文最全),插件只负责保证它一定会被问一次
配置
在 profile 的 cordis.patch.yml 里按 id 覆盖,例如:
- id: trilogy
config:
injectBudgetBytes: 24000
nudgeMaxPerSession: 5
| 键 | 默认 | 含义 |
|---|---|---|
enabled | true | 总开关 |
memoryDirName | "memory" | 记忆目录名(相对项目根) |
projectRootMarkers | [".git"] | 项目根标识 |
autoScaffold | true | 缺文件时自动创建 |
writeBootBlock | true | 往 AGENTS.md 追加 Memory 段 |
bootBlockFile | "AGENTS.md" | boot block 写进哪个文件 |
injectOnSessionStart | true | 会话开始自动注入 |
bootstrapWhenEmpty | true | PROJECT.md 还空着时,注入"去调研并填上"的指令 |
sessionsMaxEntries | 200 | SESSIONS.md 超过这个条数才把最旧的搬到归档(阈值定得高,避免过早压缩) |
projectRootStrategy | "workspace" | workspace = 工作区即项目;marker = 向上找 .git |
injectBudgetBytes | 64000 | 注入总字节预算。是「停止降级的天花板」,不是配额 —— 装得下就立刻返回。实际注入量 = PROJECT.md 全文 + DECISIONS.md 全文 + 最近 sessionEntriesInjected 条日志;SESSIONS.md 全文永远不注入,所以想让更多日志进上下文要调的是 sessionEntriesInjected |
sessionEntriesInjected | 15 | 注入最近几条 SESSIONS 条目 —— 这个键才决定有多少日志进上下文(SESSIONS.md 全文永远不注入)。15 条约占 45 KB ≈ 11k token |
nudgeOnTurnEnd | true | 收尾智能判断兜底 |
nudgeCooldownMs | 600000 | 兜底提醒冷却(10 分钟) |
nudgeMaxPerSession | 3 | 每会话兜底提醒上限(成功写入一次就清零,长会话不会因为额度用完而沉默) |
projectStaleDays | 14 | PROJECT.md 落后其余记忆文件多少天才提示陈旧;0 关闭提示 |
模板可改:三个文件和 boot block 的模板在 templates/,运行时直接读取;目录缺失时回退到内置副本。