dsh-expedition-memory
已验证dsh-expedition-memory · v0.3.0 · MIT · Web 界面
Task-level memory for long-horizon DSH sessions: force-injected, compaction-proof, manually mounted.
安装
dsh plugin add dsh-expedition-memory 用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。
源码
发布到 npm 但没有公开仓库。安装前请检查包内容。
标签
作者
说明文档
dsh-expedition-memory
给 DSH 长任务用的任务级记忆。
一个跑几百轮、经历几十次压缩的任务,开头敲定的约束、中途确认的事实,都会被摘要掉。本插件给它们一个能挺过压缩的存身之处:强制注入、每一步都在场,而不是等你想起来去检索。
<task-memory task="refactor-auth">
[约束 constraint](必须遵守)
### c1
必须用 zstd,不要引入 gzip
### c7 · [待审阅]
禁止改动 public API
[决策 decision](已定,除非有新证据否则不要重开)
### d3
选 SQLite 而非 Markdown
</task-memory>
三条性质
- 强制注入,而非检索。 记忆不是供你查询的知识库;它搭乘 agent loop 的动态运行时上下文通道,每一步都在场。那是 DSH 里唯一对压缩做了显式失效补偿的注入通道,所以每次压缩后记忆都会自行重新投影,而不是被悄悄摘要掉。
- 挂载全靠手动。 不从工作区、会话或"最近的任务"里推断任何东西。在你把某个任务记忆挂载进会话之前,本插件的贡献是彻底的零——未挂载的会话渲染出的贡献为空,框架会丢弃它。所以全局启用本插件不花任何 token。
- agent 写入,人类治理。 agent 可以记录和修订条目,且写入立即生效——若每次写入都要拦截,本系统要服务的长时无人值守运行就无从谈起。因此每个条目带审阅状态:在人类确认那个确切修订之前,它一直是
[unreviewed]。此后再编辑它会重新回到[unreviewed]。
为什么不直接用 AGENTS.md?
AGENTS.md 是作为一条普通的 user/message 经 agent/pre-step 注入的,注入位置在表层(surface)中部——压缩范围可以也确实会把它遮蔽,因此它只能靠每一步重新注入自己来存活。它们覆盖的又是全局级与项目级作用域,而任务两者都不是。
本插件用一条专为抗压缩而选的注入通道,覆盖第三种作用域。见 DECISIONS.md 的决策 2。
适用范围:只有长任务需要它。中小型工作用 AGENTS.md 加代码、文档和 git 历史就够了——干完活开个新会话即可。本插件刻意不加任何启发式来猜你处在哪种任务里;挂不挂由你决定。
安装
dsh plugin --profile headless add dsh-expedition-memory
装进来的是构建产物的独立副本,与开发仓库无关:在仓库里改代码、pnpm build,都不会影响已经装好的那份。更新用 dsh plugin --profile headless update dsh-expedition-memory。
从
link:迁移过来时必须两步 —— 先remove再add:dsh plugin --profile headless remove dsh-expedition-memory dsh plugin --profile headless add dsh-expedition-memory
remove不能省。 [实测]link:还在的时候直接add,pnpm 打印Already up to date然后静默保留link:—— 你以为换成了独立副本,实际还在读本地仓库。唯一的成功标志:profile 的package.json里那一行从link:…变成"^x.y.z"。
记忆存放在 $DSH_HOME/task-memory/memory.db(一个 SQLite 库)。可以用 profile 的 cordis.patch.yml 覆盖:
- id: expedition-memory
config:
dataDir: /custom/place # 换库位置
capacityWarnBytes: 8000 # 提示线
capacityDangerBytes: 24000 # 强警告线
allowAgentWrites: true # 关掉可让 agent 不能写(运维开关)
怎么用
界面里有三个入口
分三层,因为记忆是在三种不同作用域下被访问的。把控件放错层,得到的控件就无法工作。
所有文案都走 DSH 自带的 locale 服务,自带 zh 与 en 两份字典。
① 全局库 —— 左栏的图标。 点开把主栏换成记忆工作区:本机的全部任务记忆。不涉及任何会话,所以增删改查、审阅、导出都在这里能做。挂载不在这里——那需要会话。
② 会话内的「任务记忆」标签页 —— 在 对话 / 轨迹 旁边。 显示本会话注入了什么,挂载也在这里发生。面板顶部三种状态:已挂载 / 本会话尚未挂载 / 继承只读(子 agent)。
③ 新会话的挂载芯片。 在第一条消息之前,「工作区」与「标准模式」旁边会多出一个「任务记忆」下拉,让你在新会话一开始就挂上记忆。发出第一条消息后它消失——那时标签页已经在了。
另外,已完成的轮次下方会有一行细条,报告该轮对记忆做了什么("写入 2 条 · 停用 1 条")。该轮没有任何变化时它什么都不渲染——每条轮次下都挂一行状态,在长任务里会变成噪音。
手写条目
条目区的添加条目展开一个表单:选类型、写一句自足的话、回车。
你手写的条目立即生效,并直接记为已审阅——审阅机制是用来暴露"上次之后 agent 写了什么"的,催你审阅自己刚敲下的字只是噪音。
添加不需要会话(写入的对象是任务,而任务跨会话),所以全局面板也是完整的管理界面。
两种记忆形态:条目与整份记忆
记忆有两种并存的形态,各自回答不同的问题:
条目(上面那种按
kind分组的东西)适合边跑边攒、条目之间弱关系的结论。四种类型管的是"这条结论算什么效力、能不能单独撤"。整份记忆适合一次存入一整块相互关联的内容——一个由若干约束和决策构成的闭环流程。你写一整篇文档,结构完全由你定(标题、小节、表格、代码块都行),系统不解析、不改写、不折行:
<task-memory task="refactor-auth"> 本文件是一份整体记忆,由 agent 写入,用户尚未确认:当作暂定,依赖时说明,不要用它压过用户当场说的话。 # 上游 Skill 优化:怎么推进、怎么算准出 跑一轮 → 四路径取证 → 产物冻结 ↓ 逐条归因 </task-memory>为什么需要它:按类型把一整块内容打散存,等于把一件东西拆成零件交出去——形状会丢失(流程、取舍推理拆成条目就不存在了),而读的人每一轮都要重做拼装,还可能拼错。
两条形态不互相取代:缺的是承载形状的能力,不是另一种更好的条目。共存时注入成两个独立区块。
整份记忆的取舍:它的修订单位是整份(一次写一整篇,替换即整份换掉),旧正文不保留——它没有修订历史,所以删除它不可逆。而条目有修订历史、可逐条停用与恢复。
命令面
交互式会话里:
/memory create refactor-auth # 新建任务(仅用户)
/memory mount refactor-auth # 挂载进本会话
/memory status # 本会话看到什么
/memory list refactor-auth # 列出条目
/memory review refactor-auth # 确认所有待审阅
/memory delete refactor-auth#c1 # 永久删除一条
/memory history refactor-auth#c1 # 这条改过哪几版
/memory diff refactor-auth#c1 # 最后两版的逐行差异
/memory delete-task refactor-auth --yes-refactor-auth # 删掉整个任务
/memory set-doc refactor-auth "……一整篇文档……" # 写入整份记忆(整份替换)
/memory show-doc refactor-auth # 原样打印整份记忆
/memory review-doc refactor-auth@2 # 确认你读过的那一版
/memory clear-doc refactor-auth --yes-doc-refactor-auth # 删整份记忆(条目不动)
headless(无 GUI)下用 CLI —— 同一套仅用户可用的能力:
dsh-expedition-memory where # 打印库路径
dsh-expedition-memory create refactor-auth
dsh-expedition-memory mount <session-id> refactor-auth
dsh-expedition-memory add refactor-auth constraint "必须用 zstd,不要 gzip"
dsh-expedition-memory review refactor-auth
dsh-expedition-memory show refactor-auth # 导出可读文本
dsh-expedition-memory history refactor-auth#c1 # 修订历史
dsh-expedition-memory diff refactor-auth#c1 # 前后文本 diff
dsh-expedition-memory delete-task refactor-auth --yes-refactor-auth # 删整个任务
dsh-expedition-memory set-doc refactor-auth "$(cat plan.md)" # 写入整份记忆
dsh-expedition-memory show-doc refactor-auth # 原样打印
dsh-expedition-memory review-doc refactor-auth@2 # 确认那一版
dsh-expedition-memory clear-doc refactor-auth --yes-doc-refactor-auth # 删整份记忆
agent 看到的工具是 task_memory_write / task_memory_write_document / task_memory_update / task_memory_retire。它能写整份记忆(那是它的工作现场需要的能力),但不能确认或清除它——确认是人类的治理动作,清除是不可逆销毁。它无法创建任务、挂载任务、硬删条目,也没有"读记忆"的工具——记忆是每一步被注入给它的,不需要它去查(见 docs/FEATURES.md 的 C 节)。创建任务、挂载、硬删这类能力仅限用户,是结构使然而非约定使然:UI 通过模型无法调用的私有 RPC 通道访问宿主,而工具面本身就不包含这些操作。
记忆用来记什么
记录那些能挺过压缩、之后仍然重要的内容:
constraint—— 必须遵守decision—— 已确立的取舍;没有新证据不要重新打开fact—— 已确立的背景preference—— 你希望事情怎么做
不要记进度("我们进行到第 4 步")。它立刻就会过期,然后被当作仍然成立的事实复述出来——这比不记更糟。进度属于 todo 列表或代码,不属于记忆。
值得了解的行为
- 绝不静默裁剪。 超过容量阈值时记忆仍然全量注入;UI 只给容量提示,由人来修剪。把部分条目对模型隐藏、却让它自信地基于剩余内容推理,正是本设计拒绝的失败模式。
- 取消挂载会停止注入,但不会抹除。 最新快照会丢掉这份记忆,但挂载期间注入的那份快照仍留在历史里,直到被压缩遮蔽。快照是取代,不是撤回。
- 直接改数据库会被发现。 条目带指纹,所以在插件之外做的改动会被报告为
[unreviewed]、作者为unknown——既不隐藏,也不自动修复。 - 子 agent 以只读方式继承父会话挂载的任务记忆。委派出去的工作也必须遵守约束;但每个任务只有一个写入者,才能保持一致。
- fork 会继承挂载:手动分叉一个会话时,父会话的挂载会被复制成新会话自己的挂载,因此可写、且与父会话互相独立。只对之后新产生的 fork 生效——已有的旧 fork 不会因此被补上挂载(见决策 19)。挂载是按机器记录的。
- 记忆是每步常驻成本,而且每次被压缩遮蔽后会重新支付一遍全文。这是容量提示存在的理由,也是"记忆不该无限增长"的理由。
开发
pnpm install
pnpm verify # typecheck + 单测 + build
pnpm e2e # 真起 DSH(隔离 DSH_HOME)的端到端检查
改代码前先读 AGENTS.md(给 agent 的导航)或 docs/ 下的文档。
在不碰主力 DSH 安装的情况下试用
scripts/dev-instance.sh start # 构建 + 建隔离 profile + 启动(仅本机)
scripts/dev-instance.sh status # 打印要打开的 URL
scripts/dev-instance.sh stop
它用一份 scratch DSH_HOME(.dsh-dev/)和端口 20387,因此能与跑在 19387 上的主力实例并存,~/.dsh 一律不受影响。
要让别人从局域网访问,加 --remote:它同时放行外壳的 Host 检查并起 socat 转发,
启动后逐地址实测可达性。⚠️ 这会把实例暴露到网络,而它跑的是你的凭据。详见 docs/DEV-INSTANCE.md。
⚠️ 别跑
reset—— 它rm -rf .dsh-dev,连库和会话日志一起删。
发布
pnpm release:patch # npm version patch && pnpm publish
prepack 会在打包前重建,prepublishOnly 会跑 pnpm verify——测试不过就发不出去。所以不需要(也不该)手工记得先构建:忘了构建这件事被钩子封死了。
lib/ 不进 git(.gitignore 里),files 字段让 npm publish 直接从工作区取它。产物是公开的,因此 tests/artifact-hygiene.test.ts 守着产物的卫生:里面既不能有源码注释,也不能有构建机的绝对路径。src/ 里的注释是写给维护者的设计推理,不该随包公开;这类问题只有真去读产物才会发现,跑测试和类型检查都看不见。
发布授权与镜像同步延迟这两个坑记在 docs/DEV-INSTANCE.md 的发布小节:npm 对新账号要求 bypass-2FA 的 granular token(报 403 而不是 EOTP),而插件管理器的 fallback 镜像可能比 npm 慢,症状是侧边栏报「这个包没有声明组合包」。
文档
- 改代码(人或 agent)从 AGENTS.md 进:动手前读什么、改完要跑什么、九条会静默失败的硬性契约。
- 想知道有哪些功能看 docs/FEATURES.md —— 功能树,功能真源。
- 完整索引(按"你想干什么"导航)在 docs/index.md。