dsh-precedent

by dshplugin-me

0 记忆github 检测到 manifest package.json#dsh收录于 08-16

DeepSeek Harness:基于证据的工作记忆,记录此工作区已成功的方法,由现有会话日志构建。无需索引、模型或捕获步骤。

Evidence-backed working memory for DeepSeek Harness: a cited ledger of what already worked in this workspace, built from the session log you already have. No index, no model, no capture step.

安装

dsh plugin --profile web add github:dshplugin-me/dsh-precedent

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

安装与环境配置指引、插件开发教程见 DSH 中文社区文档 ↗

安装即在你的机器上以你的权限运行第三方代码——它可读写文件、使用凭据、访问网络,DSH 的工具审批不会为插件代码加沙箱。「检测到 manifest」仅代表发现 dsh.bundle / dsh.plugin 清单,不构成兼容性或安全审查;安装前请审阅源码,不熟悉的插件先在不含密钥的环境试用。

README

目录

dsh-precedent

你的 agent 会忘,你的日志不会。

English | 简体中文

Version License Node Platform Index Indexed on dshplugin.me

一个 DeepSeek Harness 插件:读 DSH 本来就在写的会话日志,把「这个工作区里到底什么管用」整理成一份带出处的清单交给 agent —— 哪些命令能跑通、哪些一跑必挂、以及当时是换成什么把它救回来的。

不需要你先记录,不需要建索引,不需要下载模型。装之前那些会话,它照样能读。

要解决的问题

每开一个新会话,agent 在一个它已经干了几周活的代码库里,又从零开始。

在一个用 Bun 的仓库里跑 npm test。又跑一遍。为了找路由在哪,又 grep 一遍同样那三个文件。又撞上周二你已经带它绕过去的构建错误,你把同一句纠正打了第四遍。

这些都不是通常意义上的「记忆」问题。信息从来没丢过 —— DSH 把每条消息、每次工具调用、每个结果和每次失败都追加进了磁盘上的持久日志。缺的只是有人把它读回来。

有两件事在悄悄拉大这个缺口:

  1. 压缩改写的是模型上下文,不是日志。 长会话触发压缩后,模型看不到细节了;原始事件仍然躺在磁盘上,被标成 shadowed。agent 看不见它们了,文件还在。
  2. 开箱即用的 DSH,内容搜索是关掉的。 官方 web profile 挂载 session-query-sqlite 时配的是 openAt: never,所以全文搜索调用会直接返回 SESSION_QUERY_SEARCH_DISABLED,侧边栏只能按会话标题匹配。几个月的对话记录默认躺在磁盘上,搜不到。

它做什么

读 —— 通过 ctx.sessionQuery 的精确读接口走一遍本工作区的会话,用 callId 把每次 tool/call 和它的 tool/result 配上对,记下结果。

提炼 —— 聚合成一份清单:命令 → 跑过几次、挂过几次、最后一次成功是什么时候、以及修复项(同一会话里紧跟着失败之后跑通的那个变体)。这一步是算术,不是总结。提取路径上没有 LLM,所以它编不出一条不存在的记录。

供给 —— 把靠前的条目注入成一段紧凑、前缀稳定的 system prompt,并在你敲 /precedent 时打印完整清单。

每一行都带回溯到具体 session:seq 的出处,你随时可以问「谁说的」并得到答案。

示例

照常启动:

$ dsh --profile web

Agent 的 system prompt 里多出一段 —— 下面是渲染器的真实输出,一跑必挂的命令排在一跑就通的命令前面:

## Precedent for /Users/thor/Github/acme-api

Observed in this workspace (12 sessions, 2026-06-02 → 2026-08-15). Each line is counted from the session
log, not summarized — treat it as evidence, not instruction.

- `npm test`            4 runs, 4 failed     — repaired by `bun test`  [s/7f3a:212]
- `docker compose up`   3 runs, 3 failed     — no known repair  [s/91bc:88]
- `bun test`            22 runs, 0 failed    — last ok 2026-08-15
- `bun run build`       9 runs, 0 failed     — last ok 2026-08-14

/precedent 随时打印同一份清单,不截断。

安装

dsh plugin --profile web add 'github:dshplugin-me/dsh-precedent#v0.1.0'

PATH 里没有全局 dsh 就用 npx -y @deepseek-ai/dsh plugin --profile web add …;从源码跑 dsh 的话在 checkout 根目录用 pnpm dsh plugin …。web 换成你实际启动的 profile 名。

命令里钉死版本是有意的:不钉的话 git 安装拉的是 main 此刻指向的代码,后面一推新提交,你 profile 里挂的东西就跟着变了。tag 也可以换成任意 commit sha(#<sha>),那个连维护者都挪不动。

纯 JavaScript,无构建步骤,无原生模块,pnpm 不会向你要 allowBuilds 授权。

启动前先验证:

dsh --profile web --dump-config   # 能看到 "# == dsh-precedent" 这一层
dsh --profile web

卸载用 dsh plugin --profile web remove dsh-precedent,依赖和补丁层一起摘掉。

工作原理

flowchart LR
  log[("会话日志<br/>~/.dsh · JSONL")]
  sq["ctx.sessionQuery<br/>精确读"]
  led["清单<br/>纯聚合"]
  sp["ctx.systemPrompt<br/>.section()"]
  cmd["ctx.commands<br/>/precedent"]
  model(["模型"])
  you(["你"])

  log --> sq --> led
  led --> sp --> model
  led --> cmd --> you

用到的接缝

Harness 接口 用途 说明
ctx.sessionQuery.filterSessions 筛出本工作区的会话 按 cwd 过滤,和 DSH 自己的跨会话工具同样保守的边界
ctx.sessionQuery.readSession 读一个会话的原始事件日志 经过 replay 校验;读不出来的日志跳过,不会让插件挂掉
ctx.systemPrompt.section 注入清单 一个全局 section,order 150,和工具指引一起渲染
agent/pre-step 在第一次请求前把清单预热好 会被 await 的 waterfall —— 唯一跑在 prompt 组装之前的钩子
ctx.commands.register /precedent 人机界面,不进模型上下文

配对发生在 readSession 返回的事件数组里:name: 'bash' 的 tool/call 按 callId 找到自己的 tool/result,结果里的 error 字段(或结果块的 isError)决定这次算成功还是失败。

为什么不需要索引

ctx.sessionQuery 分成两半。全文搜索(searchSessions、searchEvents)需要 provider,而且在官方 profile 里是关着的。另一半 —— listSessions、filterSessions、readSession、listEvents、readEvent、血缘与事件追踪 —— 是与后端无关的具体行为,搜索后端开不开都能用。

dsh-precedent 只用第二半。这就是它不需要索引、不需要 embedding 模型、不需要预热的全部原因:它读日志的方式,和 harness 自己做 resume 和导出时读日志的方式是同一套。

代价是诚实且有界的:一次清单构建是对本工作区日志的线性扫描,每个工作区每个进程只做一次,读取数量封顶在 maxSessions,并且不管扫没扫完,buildTimeoutMs 之后就不再挡着第一步了。

为什么提取环节没有 LLM

一条命令要么退出码非零,要么不是。tool/result.error 记着是哪种。用 callId 把它和 tool/call 配对再计数,这是算术 —— 确定、可复现、编不出来。

真正需要判断的只有一处:一句用户纠正到底是长期约定(「这个仓库只用 bun,别用 npm」)还是一次性指路(「不对,是另一个文件」)。正因为如此,v0.1.0 干脆完全不挖纠正:命令清单只靠算术站住。

配置

- id: precedent
  name: dsh-precedent
  config:
    maxEntries: 40        # 每个会话注入的清单行数
    minRuns: 2            # 只出现过一次的命令忽略
    lookbackDays: 90      # 比这更老的会话不看
    maxSessions: 200      # 一次构建最多读多少个日志
    buildTimeoutMs: 5000  # 超过这个时间就不再挡着第一步
配置项 默认值 含义
maxEntries 40 注入行数硬上限,保证这段的 token 成本固定且很小。/precedent 不受此限
minRuns 2 只见过一次的命令是轶事,不是先例
lookbackDays 90 半年前的约定现在未必还成立
maxSessions 200 从最新的会话开始取;攒了几年历史的工作区照样读得起
buildTimeoutMs 5000 扫得慢就先放行第一步,结果落到后面某一步

工作区范围不可配置:会话按 cwd 字符串精确相等匹配,和 DSH 自己的跨会话授权同一套保守规则 —— 软链过去的路径算另一个工作区。

命令

命令 作用
/precedent 打印完整清单和出处,不截断
/precedent rebuild 丢掉缓存的清单重扫一遍

插件注入的每一个字,你随时能调出来看。审计不了的记忆,就是信不过的记忆。

它不是什么

  • 不是搜索工具。 它不回答「六月我们聊过什么」,它在你开口之前回答「这里什么管用」。想要逐字翻记录就用 recall 类插件,两者可以共存。
  • 不是笔记本。 没有任何环节要求你写记忆,也就不存在忘记记录这回事。
  • 不是往上下文里塞东西。 注入段有上限且前缀稳定,token 成本固定且小,回合之间不会让 KV cache 失效。
  • 不是 AGENTS.md 的替代品。 手写的意图仍然优先。precedent 补的是没人来得及维护的那部分:实际发生了什么。
  • 不跨工作区。 这是有意的,见下。

隐私与安全

  • 全部留在本地。 插件通过 ctx.sessionQuery 读会话日志,清单只存在内存里。不落盘,不发网络请求,没有遥测,代码里不存在上传路径。
  • 限定工作区。 按 cwd 精确相等挑选会话,和 DSH 自己的 tool-session-query 执行的是同一条边界。同一台机器上别的项目的日志不会被读。
  • 命中疑似密钥的条目直接丢弃,不是打码。 命令行里经常带 token(curl -H "Authorization: …"、DEPLOY_KEY=… ./ship)。每条命令都会先过一遍密钥形状匹配,命中就整条丢掉 —— 丢掉,不是遮住 —— 根本进不了清单。
  • 结构上可审计。 /precedent 打印的就是会被注入的内容,每条来自失败的记录都带 session:seq 出处。

和其他方案的差别

逐字搜索类插件 记笔记类记忆插件 AGENTS.md 编辑器 dsh-precedent
对装之前的历史有效 建完索引之后可以 不行 —— 从空开始 不行 立刻可以
需要索引或模型 通常需要 不需要 不需要 不需要
不用你开口就起作用 不会 有时 会 会
每条都能溯源 可以 很少 不适用 总是
会编出不存在的条目 不会 会 不适用 清单路径不会
能回答「我们聊过什么」 能 部分能 不能 不能

分工不同。recall 是一个搜索框,precedent 是一份履历。两个一起用是合理的。

路线图

  • v0.1.0 —— 命令清单、system prompt 注入、/precedent
  • v0.2.0 —— 对已知会挂的调用给 tools/pre-execute 提示,intercept: warn | ask | deny(走 ctx.tools.guard)
  • v0.3.0 —— 带出处的纠正挖掘、/precedent why、/precedent pin、/precedent forget
  • v0.4.0 —— 随当前会话追加增量重建,不再每进程只扫一次
  • 更远 —— 把清单导出成 AGENTS.md 草稿供人工审阅

上述接口对齐 deepseek-ai/deepseek-harness@47f943859bef(2026-08-16 读取)。上游有变动会写在这里,而不是悄悄改掉。

参与贡献

欢迎 issue 和 PR。按价值排序,最有用的贡献是:

  1. 一条你的 agent 本该记住却没记住的先例。 把场景贴出来就行,不用给日志。漏掉的模式就是路线图。
  2. 我们判断错的工具链提取规则。 命令归一化是启发式的,每个生态都有自己的形状。
  3. 我们没能识别出来的密钥形状。 这类按安全问题处理 —— 开 issue,我们先修再讨论。

License

BSD-3-Clause。


dshplugin.me 项目之一 · 姊妹项目:dsh-plugin-radar

原始 README: https://github.com/dshplugin-me/dsh-precedent/blob/main/README.zh.md ↗