它做什么
dsh-auto-review 回答一个问题:当一个动作要越过沙箱边界时,由谁批准?它的答案是第二个模型。它在 DSH 的 approval/request 链上注册了一个应答器,把决定权交给一个只读的审查子代理——后者会读取工作区、以及已经流式传出的工具调用参数,然后返回一个结构化裁决 { decision, reason, riskLevel },而不是靠正则去猜一个是或否。
这个区别就是整个设计的要点。基于模式匹配的自动批准器在派发之前做判断,手里没有任何证据:它们匹配命令文本,然后赌一把。而这里,审查者会真的打开文件;README 也明确说明,参数中的敏感值在交给审查者之前会被脱敏。
开箱时随附的 patch 只对 bash 和 write 做 AI 审查。其他一切——包括 edit(原地修改)——都会交给人来批,直到你明确改变它。这个默认值偏保守,而且安装前就值得知道:这个插件并不会打开「全部自动批准」。
任何自动批准器都该检查的四个属性
它用的是官方接缝。 应答器只认领属于自己(ai 策略)的请求,其余全部通过 next() 委派出去。人类审批流从不会被短路,所以它是与 harness 组合,而不是替换掉 harness 的审批路径。
审查者是只读且不可再委派的。 它是一个一次性 fork,工具白名单只有 read/glob/grep。审查者自己的请求会按身份识别并委派出去,maxDepth 加上白名单让它无法再派生审查者。它能看,但不能做。
它 fail closed。 审查者崩溃、超时或返回结构不合法时,都走 fallbackPolicy,而默认值是 rejected。审查者的失败模式是拒绝,而不是悄悄放行。
每个决定都能从会话日志里重建。 链路是 approval/asked → autoReview/verdict(或 autoReview/rejection)→ approval/decided,以 ignorable 事件记录,并可选启用一个不变量伴随组件,强制标记与事件始终一致。事后你可以审计某次调用为什么被放行。
拒绝理由会回到模型
拒绝不是死胡同。审查者的理由会带着调用 id 注入到被拒的工具结果里,于是发起调用的模型知道为什么被拒,而不是反复重试同一个调用。回退与 never 策略的拒绝也会注入可审计的标记([auto-review]、[auto-review-fallback]、[auto-review-never]),并且每条注入的理由后面都会附加一段 denyGuidance 作为反绕过文本。
另外还有一个拒绝熔断器——每轮内连续 3 次拒绝,或最近 10 个裁决里有 6 个拒绝——因为一个不断被拒的模型会不断重试。
要求与安装
-
Node
^22.19.0 || >=24.0.0。 -
DSH 版本需落在声明的 peer 区间内:
>=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0。README 记录 harness 为dsh-v0.1.5-rc.2(GitHub tag,2026-09-11 验证),并说明支持双线,插件代码对两条已发布宿主线做特性探测。正是这份声明让本条目达到 L3。 -
从 npm 安装(已发布版本,预构建):
dsh plugin --profile web add dsh-auto-review -
从 git 安装(最新
main)——这条通道会在安装时构建,需要 CLI 打印出来的构建许可:dsh plugin --profile web add "github:PerryLink/dsh-auto-review#main"把打印出的
allowBuilds: { esbuild: true }写进 profile 的pnpm-workspace.yaml后重跑。如果安装停在ERR_PNPM_IGNORED_BUILDS(针对koffi或node-pty,由评测 harness 引入),运行pnpm approve-builds。 -
卸载:
dsh plugin --profile web remove dsh-auto-review。
配置
所有可调项都是 Schemastery 配置字段,可在 cordis.yml 中修改。按 id 定位的覆盖会替换整行,所以要把需要的键全部重写。对行为影响最大的几个:
| 键 | 默认值 | 含义 |
|---|---|---|
toolsPolicy.default |
human |
未列出工具的默认策略——交给人类应答器 |
toolsPolicy.overrides |
{} |
按工具的逐项策略:ai / human / never |
riskRules |
[] |
{pattern, policy, field?} 规则,在工具表之前匹配 |
fallbackPolicy |
rejected |
审查者失败时:rejected(fail closed)/ delegate / allow-once |
reviewerModel |
(继承) | 审查者模型 id;不设置则继承会话 agent 的路由 |
reviewerTimeoutMs |
60000 |
裁决截止时间;超时则套用回退策略 |
reviewerTools |
[read, glob, grep] |
审查者子进程的工具白名单(不能为空) |
maxReviewsPerTurn |
10 |
每轮 AI 裁决预算;超出后请求转为委派 |
contextBudget |
{turns: 2, maxChars: 4000} |
给审查者的精简对话记录;turns: 0 表示关闭 |
circuitBreaker |
{consecutiveDenies: 3, windowDenies: 6, windowSize: 10} |
拒绝熔断器 |
reviewerModel 是最该先看的键。不设置时,审查者会继承会话 agent 的路由——同一个模型在审查自己的请求。把它指向另一个模型,才让这次审查成为真正的第二意见;插件自己那节「为什么用第二个模型而不是规则」的论证,其实就是在为设置它做铺垫。
contextBudget.turns: 0 是 README 自己都会警告的坑:没有对话记录的审查者会拒绝用户已经授权的动作,所以当 turns: 0 撞上 ai 策略时,运行时会给告警。
已知限制
- 170 个 star 是关注度,不是审查。 本条目记录为
security: unverified;没有第三方扫描或独立审计在案,本站也没有任何条目声称 L4 或 L5。 - 默认情况下审查者与 agent 是同一个模型。 除非你设置
reviewerModel,否则你是在让一个模型带着更多证据去批准自己的请求——比正则匹配好,但弱于一个真正独立的审查者。 - 默认策略集故意很窄。 开箱只有
bash和write走 AI 审查,edit和其他一切仍然要经过你。想少点弹窗,必须自己去扩大toolsPolicy,而且是刻意地去扩大。 - git 通道会在安装时构建。 那是一块真实的安装期执行面;npm 通道提供预构建产物,可以避开它。
- 原生依赖。 评测 harness 会拉入
koffi和node-pty,在某些环境上需要pnpm approve-builds。 - 同名者众多——先确认你装的是这一个。
dsh-plugin主题下聚集了一批高度相似的「auto review」插件,都在复制同一套 Codex approve-for-me 模式;撰写时其余几个都在 0–2 star,而这个是 170。README 声明这是唯一官方仓库,其他账号下的同名仓库与其无关联。 - 审查者并不由本插件做沙箱隔离。 它是个带工具白名单的子代理;它的安全性来自「被允许调用什么」,而不是来自独立的进程边界。
何时用 / 何时不用
当你想不再为每次 bash 调用点批准,但又不愿意把决定权交给一条正则时,就用它。裁决闭环——证据进、结构化裁决出、理由回灌给模型、一切都能从日志重建——比两个极端都更站得住脚,这也是为什么本条被放进智能体合集,而不是归到便利工具里。
不要指望装完就能无人值守。默认只覆盖两个工具,除非你改配置否则审查者就是你自己的模型,而且失败模式是拒绝——这意味着一个配置糟糕的审查者会挡住工作,而不是放行。如果你要的其实是一个不再弹窗的权限模式,那是另一种形态的插件;如果你要的是按某个标准检查 agent 自己的产出,aegis 和 ouroboros 把关的是任务,而它把关的是动作。
FAQ
它会替换人类审批流吗?
不会。它增加一个应答器,只认领属于自己策略的请求,其余通过 next() 委派。它没有认领的请求,仍然和你原来一样到达你面前。
审查者失败时会怎样?
默认 fallbackPolicy 是 rejected。崩溃、超时或裁决格式不合法都会拒绝该请求,而不是放行。你可以改成 delegate(交给人)或 allow-once,但随附的默认值是安全的那个。
审查者能批准破坏性命令吗?
只有你允许才行。随附的 patch 只对 bash 和 write 做 AI 审查;一条 policy: never 的 riskRules 可以无视审查者硬禁用某个模式,而 riskPolicy.maxAutoAllow 会限制哪些 allow 裁决被采纳。README 自己举的例子就是 rm -rf / 和 git push --force。
审查者是另一个模型吗?
只有你设置 reviewerModel 才是。不设置则继承会话 agent 的路由。插件支持指定不同的供应商或模型,而那才是让「第二个模型」这个说法字面成立的配置。
怎么审计它做了什么决定?
每个决定都能从会话日志按 approval/asked → autoReview/verdict → approval/decided 重建。拒绝还会把审查者的理由带进工具结果,所以模型的上下文里就能看到它为什么被拒。

