🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

编码委派管控 jjmlovesgit/dsh-plugin-coding-delegate

DeepSeek Harness
jjmlovesgit24 天前有提交已提供中文文档扫描:含敏感能力

隔离云端规划与本地实现,写入前拦截越权操作

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/10 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add jjmlovesgit/dsh-plugin-coding-delegate
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · ads
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 24 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 72 处,展示前 72 条)
  • 读取本地文件
    experiments/delegation-ab/measure-session.cjs:57
    entries = fs.readdirSync(dir, { withFileTypes: true })
  • 读取本地文件
    experiments/delegation-ab/measure-session.cjs:65
    const stat = fs.statSync(full)
  • 读取本地文件
    experiments/delegation-ab/measure-session.cjs:104
    const buffer = fs.readFileSync(file)
  • 读取本地文件
    experiments/egress-benchmark/run-3-session-gate.cjs:133
    for (const project of fs.readdirSync(root, { withFileTypes: true })) {
  • 读取本地文件
    experiments/egress-benchmark/run-3-session-gate.cjs:136
    if (fs.existsSync(store)) hits.push(store);
  • 读取本地文件
    experiments/egress-benchmark/run-3-session-gate.cjs:200
    const { text, frames } = decodeAllFrames(fs.readFileSync(file));
  • 发起网络请求
    plugin/dist/delegation.js:588
    const response = await fetch(url, init);
  • 读取密钥环境变量
    plugin/dist/index.js:225
    parseInt(process.env.CONTEXT_TOKEN_THRESHOLD || '30000', 10);
  • 发起网络请求
    plugin/dist/index.js:561
    const outcome = await service.request({
  • 发起网络请求
    plugin/dist/index.js:607
    const outcome = await service.request({
  • 发起网络请求
    plugin/dist/index.js:635
    const outcome = await service.request({
  • 发起网络请求
    plugin/dist/index.js:1318
    const outcome = await approvalService.request({
  • 读取本地文件
    plugin/src/context.ts:80
    const fileSize = fs.statSync(resolvedPath).size
  • 读取本地文件
    plugin/src/context.ts:94
    raw = fs.readFileSync(resolvedPath, 'utf8')
  • 读取本地文件
    plugin/src/contracts.ts:13
    return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex')
  • 读取本地文件
    plugin/src/contracts.ts:348
    exists: (p: string) => boolean = (p) => fs.existsSync(p)
  • 写入本地文件
    plugin/src/contracts.ts:365
    fs.mkdirSync(path.dirname(target), { recursive: true })
  • 写入本地文件
    plugin/src/contracts.ts:368
    fs.writeFileSync(temp, JSON.stringify({ version: 1, records }, null, 2), 'utf8')
  • 写入本地文件
    plugin/src/contracts.ts:393
    fs.renameSync(from, to)
  • 写入本地文件
    plugin/src/contracts.ts:426
    fs.mkdirSync(path.dirname(lockPath), { recursive: true })
  • 读取本地文件
    plugin/src/contracts.ts:437
    if (Date.now() - fs.statSync(lockPath).mtimeMs > REGISTRY_LOCK_STALE_MS) {
  • 删除本地文件
    plugin/src/contracts.ts:438
    fs.rmSync(lockPath, { force: true })
  • 删除本地文件
    plugin/src/contracts.ts:454
    fs.rmSync(lockPath, { force: true })
  • 读取本地文件
    plugin/src/contracts.ts:492
    text = fs.readFileSync(resolveDelegatedRegistryPath(), 'utf8')
  • 读取本地文件
    plugin/src/declaration-egress-hook.ts:129
    return fs.statSync(resolveScope(scope)).isDirectory()
  • 读取本地文件
    plugin/src/declaration-egress-hook.ts:202
    if (fs.statSync(resolveScope(token)).isDirectory()) return true
  • 读取本地文件
    plugin/src/declaration-egress-hook.ts:215
    return fs.existsSync(resolved)
  • 读取本地文件
    plugin/src/declaration-egress-hook.ts:232
    const stat = fs.statSync(p)
  • 读取本地文件
    plugin/src/declaration-egress-hook.ts:239
    entries = fs.readdirSync(p, { withFileTypes: true })
  • 读取本地文件
    plugin/src/declaration-egress-hook.ts:261
    text = fs.readFileSync(skeleton, 'utf8')
  • 执行外部命令固定命令
    plugin/src/delegation.ts:64
    const out = child_process.execFileSync('git', ['-C', workspaceDir, 'rev-parse', 'HEAD'], {
  • 执行外部命令固定命令
    plugin/src/delegation.ts:97
    child_process.execFileSync('git', ['-C', workspaceDir, ...command.args], {
  • 发起网络请求
    plugin/src/delegation.ts:765
    const response = await fetch(url, init)
  • 读取本地文件
    plugin/src/delegation.ts:1102
    if (!fs.existsSync(workspaceBase)) {
  • 写入本地文件
    plugin/src/delegation.ts:1104
    fs.mkdirSync(workspaceBase, { recursive: true })
  • 读取本地文件
    plugin/src/delegation.ts:1475
    privateKeyPem = fs.readFileSync(privateKeyPath, 'utf8')
  • 读取本地文件
    plugin/src/emission.ts:262
    if (!patchBlocks && fs.existsSync(resolvedPath)) {
  • 读取本地文件
    plugin/src/emission.ts:281
    if (!fs.existsSync(resolvedPath)) {
  • 读取本地文件
    plugin/src/emission.ts:291
    original = fs.readFileSync(resolvedPath, 'utf8')
  • 写入本地文件
    plugin/src/emission.ts:310
    fs.mkdirSync(parentDir, { recursive: true })
  • 写入本地文件
    plugin/src/emission.ts:311
    fs.writeFileSync(resolvedPath, fileCode, 'utf8')
  • 读取本地文件
    plugin/src/guard.ts:396
    const stat = fs.statSync(resolved)
  • 读取本地文件
    plugin/src/guard.ts:398
    return fs.readFileSync(resolved, 'utf8')
  • 读取本地文件
    plugin/src/guard.ts:612
    const sourceStat = fs.statSync(sourcePath)
  • 读取本地文件
    plugin/src/guard.ts:613
    const declarationStat = fs.statSync(declarationPath)
  • 读取本地文件
    plugin/src/index.ts:488
    if (typeof candidate === 'string' && candidate && fs.existsSync(candidate)) {
  • 读取本地文件
    plugin/src/index.ts:499
    if (typeof value === 'string' && value && fs.existsSync(value)) {
  • 读取密钥环境变量
    plugin/src/index.ts:598
    parseInt(process.env.CONTEXT_TOKEN_THRESHOLD || '30000', 10)
  • 发起网络请求
    plugin/src/index.ts:1005
    const outcome = await service.request({
  • 发起网络请求
    plugin/src/index.ts:1057
    const outcome = await service.request({
  • 发起网络请求
    plugin/src/index.ts:1094
    const outcome = await service.request({
  • 读取本地文件
    plugin/src/index.ts:1516
    content = fs.readFileSync(skeleton, 'utf8')
  • 发起网络请求
    plugin/src/index.ts:1846
    const outcome = await approvalService.request({
  • 写入本地文件
    plugin/src/logging.ts:51
    fs.mkdirSync(path.dirname(LOG_FILE), { recursive: true })
  • 写入本地文件
    plugin/src/logging.ts:52
    fs.appendFileSync(LOG_FILE, entry, 'utf8')
  • 读取本地文件
    plugin/src/paths.ts:57
    const stat = fs.lstatSync(ancestor, { throwIfNoEntry: false })
  • 读取本地文件
    plugin/src/paths.ts:94
    if (fs.lstatSync(current, { throwIfNoEntry: false })) return { ancestor: current, tail }
  • 读取本地文件
    plugin/src/paths.ts:137
    const stat = fs.lstatSync(current, { throwIfNoEntry: false })
  • 写入本地文件
    plugin/src/sandbox.ts:303
    fs.writeFileSync(shim, SANDBOX_PREFLIGHT_SOURCE, 'utf8')
  • 删除本地文件
    plugin/src/sandbox.ts:329
    fs.rmSync(dir, { recursive: true, force: true })
  • 读取本地文件
    plugin/src/savings-tracker.ts:351
    if (!fs.existsSync(this.ledgerPath)) return null
  • 读取本地文件
    plugin/src/savings-tracker.ts:352
    return JSON.parse(fs.readFileSync(this.ledgerPath, 'utf8'))
  • 读取本地文件
    plugin/src/savings-tracker.ts:381
    if (fs.existsSync(this.ledgerPath)) {
  • 读取本地文件
    plugin/src/savings-tracker.ts:382
    const raw = fs.readFileSync(this.ledgerPath, 'utf8')
  • 写入本地文件
    plugin/src/savings-tracker.ts:450
    fs.mkdirSync(path.dirname(this.ledgerPath), { recursive: true })
  • 写入本地文件
    plugin/src/savings-tracker.ts:451
    fs.writeFileSync(this.ledgerPath, JSON.stringify(ledger, null, 2), 'utf8')
  • 写入本地文件
    plugin/src/verification.ts:495
    fs.mkdirSync(dir, { recursive: true })
  • 执行外部命令来自配置/变量
    plugin/src/verification.ts:498
    result = child_process.spawnSync(binary, args, {
  • 读取本地文件
    plugin/src/verification.ts:525
    return fs.readFileSync(file, 'utf8')
  • 删除本地文件
    plugin/src/verification.ts:533
    fs.rmSync(file, { force: true })
  • 写入本地文件
    plugin/src/verification.ts:663
    fs.mkdirSync(path.dirname(rawLogPath), { recursive: true })
  • 写入本地文件
    plugin/src/verification.ts:664
    fs.writeFileSync(rawLogPath, output, 'utf8')
扫描于 2026/11/3(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 隔离云端规划与本地实现
  • 写入前拦截越权操作
  • 记录哈希绑定晋级校验

DeepSeek Harness 的预防式治理插件:云端规划器禁用写入与 shell,本地执行者在受限工作区内实现,晋级与机器校验或操作员背书的记录哈希绑定。五道边界,每道都失败即关闭。

README

由 DeepSeek 最新模型翻译生成
DSH 编码委派技术控制:职责分离 一个 DeepSeek Harness(DSH)插件,把谁规定工作与谁实现工作分开,并且不允许前者写后者的代码。这是技术控制,不是策略:拦截发生在写入落地之前的工具调用钩子里,所以不依赖模型自觉遵守。 计量模型没有写入工具,也没有 shell。一个被完全提示词注入的架构师可以随便规划,却依然改不了你主机上的一个字节,因为权限从未授予。 工作原理:交出契约,拿回裁决 编码需要完成两种不同的工作,而它们想要两种不同的上下文。插件给各自一个窗口,只让两样东西在两者之间穿过。 架构师是计量思考模型。它主持设计对话,决定工作如何拆分,并为每个单元写一份契约:要构建什么、worker 可以写哪里、以及判定该单元是否通过的命令。它不写源码,也不回读源码。 worker 是你 GPU 上已经在跑的东西。它接收一个单元和该单元所需的一切——仅此而已——写代码,然后被丢弃。每个单元一个全新上下文,不花什么成本。 | 方向 | 穿过的东西 | 永不穿过的东西 | | 架构师 → worker | 契约:指令、允许的路径、验证命令 | 设计对话、其他单元 | | worker → 架构师 | 裁决:通过/失败计数、脱敏的失败结构、写入文件的文件名 | 代码 | 验证命令作为普通子进程运行,需操作员批准。
展开完整文档(README 剩余 1 节)
DSH 编码委派技术控制:职责分离

一个 DeepSeek Harness(DSH)插件,把谁规定工作与谁实现工作分开,并且不允许前者写后者的代码。这是技术控制,不是策略:拦截发生在写入落地之前的工具调用钩子里,所以不依赖模型自觉遵守。

计量模型没有写入工具,也没有 shell。一个被完全提示词注入的架构师可以随便规划,却依然改不了你主机上的一个字节,因为权限从未授予。

工作原理:交出契约,拿回裁决

编码需要完成两种不同的工作,而它们想要两种不同的上下文。插件给各自一个窗口,只让两样东西在两者之间穿过。

架构师是计量思考模型。它主持设计对话,决定工作如何拆分,并为每个单元写一份契约:要构建什么、worker 可以写哪里、以及判定该单元是否通过的命令。它不写源码,也不回读源码。

worker 是你 GPU 上已经在跑的东西。它接收一个单元和该单元所需的一切——仅此而已——写代码,然后被丢弃。每个单元一个全新上下文,不花什么成本。

| 方向 | 穿过的东西 | 永不穿过的东西 |
| 架构师 → worker | 契约:指令、允许的路径、验证命令 | 设计对话、其他单元 |
| worker → 架构师 | 裁决:通过/失败计数、脱敏的失败结构、写入文件的文件名 | 代码 |

验证命令作为普通子进程运行,需操作员批准。它的原始输出留在本地机器;回传的是失败结构,源码已被剥离。

状态:0.2.0, 机制可用且经过测试。它的局限有文档记录,而非粉饰,包括两个无法从进程内部关闭的——见本控制未覆盖的内容。决定它是否适合你的情况之前,先读那一节。

它做什么

五件事,按作用顺序排列:

1. 进程内,无 sidecar。 没有守护进程,没有额外端口,没有要监管的东西。闸门和作者身份守卫都在插件内运行。
2. 每个出站请求上的 DLP 闸门。 提示词在云端看到之前会被扫描凭据和高熵 token。命中就拒绝或改道到本地 worker,绝不传输。闸门会累积它见过的用户消息,所以早前轮次里的凭据会让它保持关闭,而不是滚出视野。
3. 双向的代码守卫。 云端编写的源码写入和删除会被拒绝或送审——回读 worker 写过的文件也一样,因为那会把委派的代码进入上下文委派的存在,正是为了把它挡在外面。Shell 形式也覆盖了,包括内联程序文本(python -c、node -e)。
4. delegate_worker。 架构师调用这个工具,把一单元实现交给本地 OpenAI 兼容服务器(LM Studio、Ollama、vLLM、llama.cpp、远程网关)。文件写入被限制在工作区内,验证输出在传输前会脱敏为结构,验证命令本身需要批准。
5. 一单元是被判定的,不是被报告的。 契约用 contractFiles 钉住——在 worker 运行前哈希,拒绝作为写入目标,运行后重新哈希,所以任何改动都会让判定作废——一单元如果写了文件却没验证,就报告 UNVERIFIED。整文件输出可以创建文件,不可以修改文件。然后 coherenceVerification 运行项目自己的命令,有权作废一单元——即使它自己的测试通过了,但整棵树没有。

运作方式

架构师可以推理,但不能撰写。worker 可以撰写,但不能越界。两者未经同意都不得执行。源代码不离开本机。

这里的每条规则都是这句话的一个实例——除了规则 8,它讲的是源代码可以去哪里——而且每条都失败关闭:如果一条规则无法评估,或者批准服务联系不上,答案就是否。

| # | 规则 | 由谁执行 |
| 1 | 凭据不得到达云端 | DLP 门:拒绝,或钉在本地 |
| 2 | 架构师不得撰写或删除源代码 | 代码守卫:拒绝,或走批准门 |
| 3 | 架构师不得读回它委派出去的东西 | settled 规则:一单元通过后未改动的文件静默读取,失败、未验证以及此后被编辑过的文件会询问;delegateReadPolicy: 'allow' 放宽这一切,对所有智能体生效,并且会说明 |
| 4 | worker 不得写到工作区之外 | 对每条输出路径做限制 |
| 5 | worker 的代码不得在服务器内运行 | 只用子进程;进程内回退关闭 |
| 6 | 架构师提出的命令不得未经检查就运行 | 批准接缝 |
| 7 | 委派的结果是判定,不是声明 | 写了文件却没验证的,报告 UNVERIFIED |
| 8 | 源代码不得到达云端 | 携带围栏源代码的云端请求默认拒绝;由 sourceEgress 决定 |

规则 8 是启发式的:它寻找带源代码语言标签、至少三行的围栏代码块,所以没打标签粘贴的源代码、用散文描述的源代码,或者拆成短块的源代码,都不会被检测到。它也是唯一一条能拒绝你自己输入的请求的规则。

强制的不变量

五条边界,每条都说明它不覆盖什么,因为边界计数只有在每一项都是它所声称的那种边界时才有意义。

| # | 边界 | 由谁执行 | 如何失败关闭 |
| 1 | 变更完整性 | tools/pre-execute 拦截云端写入与 shell 执行 | 规划层在物理上无法在宿主机上写入或运行 |
| 2 | 出口隐私 | tools/post-execute 通过 sourceReadEgress: 'declarations' 提供 .d.ts 桩文件 | 若声明缺失或早于其源文件,读取会被拒绝 |
| 3a | 工作区根目录 | workspaceDir + emitAllowlist | 无条件生效 —— worker 无法逃出沙箱目录 |
| 3b | 任务单元范围 | targetFiles、unitScope: 'enforce' | 有条件生效 —— 未声明的路径会被拒绝,但什么都不声明的单元在整个工作区内不受限制 |
| 4 | 不稳定因素隔离 | runVerification 默认跑 3 轮 | 非确定性漂移会记录 UNIT_FLAKY 并中止晋级 |
| 5 | 晋级套接字 | scripts/check-promotion.cjs | 裁决之后的任何编辑都会把退出码翻成 1 |

其中三项带限定条件,而这些限定条件比表格本身更重要:

- 第 3b 行是可选启用的。 工作区根目录是硬边界;单元边界只在架构师声明了它时才存在,而且没有任何机制强制声明。把两者混为一谈,就会让一张表读起来像五条无条件边界,而其中一条其实是契约属性。
- 第 2 行是来源追溯,不是验证。 读取被重定向到构建产出的声明文件,过期与否靠 mtime 判断 —— 这只证明发生过重新构建,一次 touch、一次 checkout 或时钟偏移就能骗过它。tsc 是被信任的,不是被证明的。
- 第 5 行约束的是内容,不是对某个人的身份认证。 一条 OPERATOR_ATTESTED 记录保存一个 SHA-256 和两个自报字符串。编辑文件会把套接字翻成 1,但没有任何机制验证署名操作者确实做了评审。这是防篡改证据,不是密码学意义上的不可否认性 —— 没有密钥,没有签名,也没有第三方。

面向企业评审

企业评估混合框架时,卡住的地方通常是结构,而不是硬件效率或 token 成本。反复出现的反对意见是:一个能访问宿主机工具的云端智能体,靠的是提示词指令(「不要修改范围外的文件」)或被动弹出的审批框 —— 这种许可是暂停,不是边界;而且作者自己给自己的作品打分并提交。

这里有三点直接回应了这个问题,每一点旁边都写明了它的局限,因为一个隐藏了局限的控制项,正是企业评审存在的意义所在。

1. 职责分离是机制性的,不是靠指令。 云端模型是架构预言机。它在 tools/pre-execute 处被拦下,无法改动文件、无法执行 shell —— 在 control-bypass.test.cjs 的十五条路径中,四条被直接拒绝,十一条被挂起等待审批,没有一条能在未获授权的情况下触达源码。变更权限归属于本地 worker,且被限制在受约束的工作区内。
限制: 工作区根目录是无条件边界,但按文件的 targetFiles 限制以声明为条件——不声明任何内容的单元在整个工作区不受限制。强制声明的策略是合理诉求,但尚未内置。

2. 晋升是防篡改的,而不是凭感觉检查。 Git 显示提交,但不显示字节由远程模型还是经认证的本地单元产出。晋升套接字把文件绑定到 SHA-256,该哈希在盒上共识期间注册(三次运行,非确定性漂移记录为 UNIT_FLAKY)或经人工审查(OPERATOR_ATTESTED)。裁决后的任何编辑都会使其失效,套接字以 1 退出。promotion-socket.oracle.mjs 覆盖全部十二种判定情形,并且在 CI 中运行——缺失的裁决分支正是它要捕获的 bug,因为落入通用拒绝与正确的严格性无法区分。
限制: 注册表是每机器本地的,不在仓库中,所以套接字是本地 pre-commit 门禁,而非 CI 门禁;并且 operator 是自报字符串,没有密钥也没有签名。那是防篡改,不是密码学不可否认性。

3. 出口受构建来源约束。 使用 sourceReadEgress: 'declarations' 时,对 .ts 文件的读取以编译器生成的 .d.ts 存根应答,因此架构师获得类型和签名,而不摄入实现体。在本仓库上实测:所服务的声明中 for/while、if/switch 和 fs. 调用为零,而源码中分别为 16、80 和 2。
限制: 构建是受信任的,而非经验证的——陈旧性通过 mtime 检查,touch、检出或时钟偏移都能击败它;并且该选项默认关闭,需要重启插件。

企业审查会发现缺失什么

在此陈述,而非在采购对话中被发现:

- 注册表是本地、未签名且每机器独立的。 审计记录不能只存在于笔记本电脑上;它们需要用真实身份签名,并发送到中央清单或证明存储。
- 证明不是持久的。 后续委派触及同一文件会取代该记录——语义正确,因为裁决描述的是内容,但这意味着人工证明必须重新建立,不是永久证书。
- 任务范围界定是选择加入的,如上所述:没有任何东西强制架构师声明 targetFiles。
- 0.2.0 的个人项目。 API 未冻结。诚实的限制被记录下来而非粉饰,这是评估应当权衡的加分特质,因为它太罕见了。

主张不是这能削减计量账单——实测,那大约值十五美分。而是本地硬件成为有记录支撑的边界,并且指定工作的模型可证明不是编写工作的那个模型。

这项控制不覆盖什么

有效性声明是控制的一部分,不是它的附录。以下是各项限制,也正是你该读这个文件、而不是读功能列表的原因。

- 它拦的是写入,不是意图。 守卫看到的是工具调用和 shell 文本。模型在对话中、在一次计算中、经由第二条工具路径、或经由本插件之外的任何插件或 MCP 服务器产出的源码,它都看不见。这是范围边界,不是缺陷;也就是说,这项控制的覆盖范围是本插件的写入路径,而不是「模型没有写代码」。
- 记录器与被记录者跑在同一个进程里。 守卫、worker 和账本都活在同一个 DSH 进程内,所以下面的记录是「发生了什么」的证据,不是「没有别的事情发生」的证明。哈希对 worker 约束得很好;这里没有任何东西约束 记录器。要堵上这一点,需要一个进程无法反向触及的外部接收端,那超出了本插件的范围。
- 它不会让编码更便宜、更私密或更长久。 本插件最初正是靠这三条主张立足。每一条都做了测试,每一条都不成立;测量结果放在 已撤回的主张 里,而不是删掉,因为一位作者公开了反证的控制,比一份干净的功能列表更有用。
- 守卫并不精确。 一条 shell 命令只要点到了某个目录,而该目录包含被委派的文件,就会被拒绝,哪怕它只是列个名字;删除动词只要和某个源文件名出现在同一行,就会被拒绝,哪怕目标毫不相干。两者都是失败即关闭——代价是,一旦有委派落地,日常的清理维护就跑不动了。已记录,尚未修复。
- 审计记录覆盖的是委派,不是全部。 账本里架构师侧的计数器(totalCloudTokens、architectTurns、totalSpendUSD)在结构上恒为零:本该喂给它们的主机事件不带用量。计量模型读过什么,记录在 SOURCE_READ 追踪里,那是日志文件,不是受追踪的记录。所以这条线索能回答「委派了什么、结果如何」,对其余部分保持沉默。
- 这里没有任何防篡改。 注册表和账本都是普通的本地 JSON。任何对数据目录有写权限的人都能改。

已撤回的主张,以及原因

每一行都是在本仓库自己的工作上测出来的。保留它们,是因为一项控制的公信力来自它披露了什么,也因为每一条都是给下一个做类似东西的人埋的坑。

| 主张 | 测量结果说明了什么 |
| 「你的计划负责思考,GPU 负责打字」 | 作为机制成立,作为节省几乎一文不值。329 次委派中,架构师计费了 666,756,560 个输入 token;本地 worker 的全部输出是 548,106 —— 占账单的 0.08%。委派无法有效削减一个它只贡献 0.08% 的总量。 |
| 「跑在你自己的机器上,所以是私密的」 | 被推翻。 架构师必须读源码才能针对它做工程,而它读过的所有内容都会在之后的每一轮重新发送 —— 实测每轮约 8.5 次读取事件。留在本地的是打字,不是对所打内容的了解。 |
| 「本地路由省钱」 | 被推翻,而且文件底部从未这样声称。 委派输出折合云端等价价值 $0.1047;硬件回本大约是这个工作负载的 19,000 倍。 |
| 「有容量,所以计划能撑住」 | 无证据支持。 会话长度由上下文窗口填满决定,而填满它的主要是架构师的读取,插件并不减少这部分。能证明它延长会话的实测证据:没有。 |
| 再加一层,在本地读仓库,把架构师挡在代码之外 | 建过,测过,已退役。 这一层的窗口放不下;某个按模型设置的推理参数无法覆盖;卸载打字换回的收益远少于它交还的读取量;没有任何由 lead 编写的契约被派发并验证过。src/index.ts 的拆分后来让这四条中的第一条退役,所以这个决定建立在其余三条上。见 docs/ROADMAP.md。 |

更普遍的教训,比这个插件活得更久:你无法通过改变谁来打字来削减会话的计费成本。你要削减的是规划模型必须持有的东西。 任何以「写作很贵」为前提的架构,都用错了成本模型。

证据链

一次委派之后,审查者能查到的东西,全部在本地:

| 记录 | 它回答什么 |
| contractFiles 的哈希,前后各一份 | 实现期间规格是否被改动?一旦改动,判定作废(CONTRACT_MODIFIED) |
| 委派注册表 | 某个单元写了哪些文件、它们的 sha256、是新建还是打补丁,以及判定结果和时间戳 |
| 节省账本 | 每一次委派调用:token、耗时、结果 |
| SOURCE_READ 追踪 | 架构师读了哪些源码,含路径、范围和哈希 |
| CONTEXT_QUALITY 追踪 | 每次调用的提示词大小、峰值、压缩次数、回收的 token,以及这些数字属于哪条路由 |

判定有四种,不是两种。 UNIT_PASSED、UNIT_FAILED、UNIT_UNVERIFIED、UNIT_FLAKY —— 委派一次编辑却没给验证命令,这是最常见的情况,它既不算通过也不算失败,把它算作失败会污染它本就是为了产出的那个数字。通过的单元没改动的文件会静默读回;失败、未验证、不稳定以及此后被改过的文件则会追问。
UNIT_FLAKY 之所以存在,是因为非确定性判定器——属性测试、并发测试框架——可能在缺陷没触发的那一轮,让一个坏实现通过;而「通过」这个结论,正是敲定一个文件的东西。runVerification 默认跑三次:三次结论一致,说明契约稳定;只要出现分歧,就记为 flaky——不算通过,不算敲定,并且点名判定器而不是代码。这是这条控制项以前唯一可能发出的假绿灯,而且它是静默的。

三倍的开销是刻意的,在你动手测量任何东西之前值得先知道。你已经测出是确定性的测试套件,可以传 verificationRepeats: 1 把时间省回来;快路径才是需要你做决定的那条。循环只在出现分歧时短路,因为那是唯一一个再跑也改变不了的结果——所以一个 flaky 单元花两次运行,干净通过或干净失败都要花满三次。

环境要求

- Node.js 22+
- 本地 OpenAI 兼容服务器,如果你想用本地路由或 delegate_worker (默认是 127.0.0.1:1234 上的 LM Studio;其他服务用 localEndpoint 指定)
- 云服务商,供架构师角色使用(默认 DeepSeek)

不需要容器运行时。 验证以普通子进程运行。容器是可选的加固手段——见 Verification。

安装

插件位于 plugin/。DSH 加载的是配置档 bundle,所以把它注册进你在用的配置档:

The CLI profile is web; the desktop app boots tauri.
.\scripts\register-plugin.ps1 -Profile web

或者手动来,脚本做的也就是这些:

dsh plugin --profile <name> add ./plugin
then add "dsh-plugin-coding-delegate" to dsh.profile.bundles in
~/.dsh/profiles/<name>/package.json

配置

插件自带的默认值指向 127.0.0.1:1234 上的 LM Studio,模型是 qwen/qwen3.8-27b。在你的配置档 cordis.patch.yml 里覆盖它们;plugin/cordis.patch.example.yml 是一份完整可用的示例,涵盖插件设置、一个 LM Studio 服务商和一个 DeepSeek 服务商。

大家最常需要改的两项设置:

- id: local-router
config:
localModel: 'Qwen/Qwen3-Coder-30B-A3B-Instruct'
localEndpoint: 'http://192.168.1.50:8000/v1' # vLLM, Ollama, llama.cpp, a gateway

有一项设置决定一个单元能否自我验证。 委托的验证命令会被拒绝,除非程序在允许列表里,或者已授予批准;这属于运维配置,不是工具参数——刻意如此,这样模型就没法把它关掉:

verificationAllowlist: ['node'] # a delegated node … command runs unattended

它匹配的是程序,不是参数,所以把 node 加进允许列表,也就等于允许 node -e "<anything>"。优先用它,而不是 verificationApproval: 'allow',后者的范围严格更宽。
完整配置参考、服务商设置和所有安全密钥:plugin/README.md。
那才是真正的文档,本文件只是摘要。

第一个单元

委派在架构师这边只是一次工具调用。单元声明要构建什么、可以碰哪些文件、给 worker 看什么,以及用哪条命令判定它是否通过:

{
"taskName": "parse-iso-duration",
"instruction": "Implement parseIsoDuration(text) in src/duration.ts. Return milliseconds; throw a TypeError on malformed input.",
"targetFiles": ["src/duration.ts"],
"contextFiles": [{ "path": "src/duration.ts", "startLine": 1, "endLine": 40 }],
"contractFiles": ["tests/duration.test.ts"],
"runVerification": "npx vitest run tests/duration.test.ts"
}

代码永远不会回来。回来的是判定结果——以下只是示例,但每个字段名和措辞都是插件实际打印的内容:

Task 'parse-iso-duration' completed. Wrote 1 file(s):
- src/duration.ts (84 lines, 2410 bytes, patched in place with 1 hunk(s))
Workspace: C:\Projects\app (resolved via caller-supplied workspaceDir)
Verification Results: Passed 12, Failed 0.
Coherence check: Passed 305, Failed 0.
Contract: 1 declared file(s), unchanged.

把它读成四条断言,因为它们分别接受检查:

- Wrote 1 file(s) —— 写入落地了,在工作区之内,而且只落在单元声明的路径上。
- patched in place with 1 hunk(s) —— worker 编辑的是给它看的那个文件,而不是替换它。
这个动词就是边界:整文件写入可以创建文件,绝不能修改文件。
- Passed 12, Failed 0 —— 你的验证命令通过了。它没有任何部分靠信任采信;命令本身经过批准,而 Coherence check 是项目级闸门,即使单元自己的测试通过,它也能让单元作废。
- Contract: 1 declared file(s), unchanged —— 判定该单元的那份测试,与你钉住的那份逐字节一致。如果不是,判定就作废。

回执里缺失的东西才是发现。写了文件却没验证的单元报告 UNVERIFIED;测试通过但代码树不一致的报告 INCOHERENT。两者都不是 SUCCESS,也都不会按 SUCCESS 报告——委派结果是判定,不是声明。

操作要求:自验证委派需要顶层会话

委派单元无法从子代理内部验证自己,这是设计使然——不是要绕开的 bug。 DSH 把子智能体的 approvalPolicy 钉死为 'never',所以审批接缝不存在,验证命令会被确定性地拒绝。你会看到 VERIFICATION_NOT_APPROVED,原因是 "approval was not granted";如果你的提示词禁止架构师自己跑测试,单元就会一直迭代,永远不收敛。

两件事能让循环闭合:

1. 从顶层会话运行委派,而不是子代理或嵌套作用域。
2. 放行程序。 委托的验证命令会被拒绝,除非它的程序在允许列表里,或者已获得批准。这是运维侧的配置,不是工具参数——这是有意为之,模型无法把它关掉:

- id: local-router
config:
verificationAllowlist: ['node']

允许列表匹配的是程序,不是它的参数,所以放行 node 也等于放行 node -e "<anything>"。优先用它,而不是 verificationApproval: 'allow',后者范围严格更宽。

两者都没有时,架构师会退回到自己运行裁判——在一个任务上实测,这要花验证循环 179,840 token,加上周边 440,500 token,而循环留在契约内时只需一次委托调用。

检查委托的工作是否经过验证

仓库可以只凭裁决结果做门禁,插件完全不碰 git:

node scripts/check-promotion.cjs --changed # pre-commit: nothing changed since its verdict
node scripts/check-promotion.cjs --path src/x.ts # one file

退出码 0 表示已定案;1 表示未定案;2 表示问题无法回答——注册表读不出来就是拒绝,绝不算通过。它会重新计算每个文件的哈希,因为裁决描述的是内容:一个文件通过之后又被编辑,它就不是任何验证所针对的版本了。它覆盖委托的 worker 写过的文件;架构师写的或手写的文件没有记录,会报告为未知。

这里不声称能做到的事

- 补丁必须精确匹配,过期的补丁会失败。 worker 返回的要么是整份文件,要么是搜索/替换增量,逐字节对照它当时看到的内容匹配。没有模糊匹配,所以对不上就拒绝,不会近似处理。这里没有任何机制让 worker 发现代码;它只能编辑交给它的东西。
- 整文件输出是新建,不是修改。 写到已存在的路径会被拒绝,无论新内容有多大。整份文件仍然可以整体替换,办法是发一个补丁,其搜索文本就是该文件当前的全部内容——这需要架构师把内容注入进去,因为 worker 读不到它。
- 读保护分不清智能体谁是谁。 DSH 不向插件暴露智能体的血缘,所以保护对所有智能体一律失败关闭,而不是区分架构师和子代理。智能体是什么不再决定它能读什么——已定案的规则才决定。
- 委托单元无法在子代理内部自我验证。 DSH 把子智能体的 approvalPolicy 钉死为 'never',所以批准这一环不存在,验证会被确定性地拒绝。自我验证的委托需要顶层会话。这是实测结果,不是本插件能覆盖的。
- 它不会让本地模型变得和云端模型一样强。
- 服务商传输、工具 schema 强制、会话存储都在 DSH 里,不在这里。

仓库结构

| path | what it is |
| plugin/ | 插件本体、测试和完整文档 |
| experiments/delegation-ab/ | 产出已废弃结论的 A/B 协议,包括那次无法执行的运行以及原因 || experiments/contract-first/ | 一份无法满足的契约,留作证据,以及它修正后的兄弟版本 |
| docs/findings.md | 发现的缺陷,以及每个缺陷的代价 |
| docs/experiment.md | 测量数据,包括那些对插件不利的结果 |
| docs/control-effectiveness.md | 五点设计对照实际强制、实际测试、或仅停留在文档上的部分 |
| docs/verification-architecture.md | 为什么这个循环必须把验证放在本机,以及唯一一个这套推理不成立的层级 |
| docs/ROADMAP.md | 构建了什么、测量了什么、废弃了什么 |
| scripts/check-promotion.cjs | 晋升接口:根据委派的工作是否已验证,决定是否放行一次提交 |
| scripts/measure-reading-cost.cjs | 架构师实际读了什么,数据来自插件自己的审计轨迹 |

开发

cd plugin
npm run build # tsc
npm run test # vitest, unit
npm run test:oracles # node --test, contract oracles
npm run test:all

在仓库根目录:

node scripts/check-readme-consistency.cjs # the two policy tables must agree
node scripts/check-dist-in-sync.cjs # rebuilt dist must be staged
node scripts/check-contract.cjs --spec # specification-conformance suite

安全

插件经过外部审查,对这次审查的回应——包括发现的缺陷和未修复的缺陷及原因——都在 SECURITY-REVIEW.md 里。

许可证

MIT —— 见 LICENSE。包内自带一份副本,位于 plugin/LICENSE,因为发布出去的产物是独立的。
预览分享卡片长什么样 ↓jjmlovesgit/dsh-plugin-coding-delegate
分享 · DeepSeek Harness Hub
jjmlovesgit/dsh-plugin-coding-delegate

隔离云端规划与本地实现,写入前拦截越权操作

这是你的仓库?认领条目

回到顶部