首页
/ caveman cavecrew-builder 子代理设计详解:1-2 文件外科编辑、Diff 收据与拒绝协议

caveman cavecrew-builder 子代理设计详解:1-2 文件外科编辑、Diff 收据与拒绝协议

2026-09-06 16:21:49作者:董斯意

本篇技术文章以 plugins/caveman/agents/cavecrew-builder.md 这一子代理定义文件为核心,完整拆解 caveman 项目中 cavecrew-builder 的职责边界(只允许 1-2 个文件的编辑)、四步工作流、path:line-range 收据输出契约与四类终止性拒绝行,并结合 src/hooks/cavecrew-model-overrides.js 等仓库源码,说明该定义文件如何被模型覆写 Hook、插件同步机制和 opencode 安装器消费,读完可掌握一个"输出即证据"的低 token 编辑型子代理的完整设计范式。

它在 caveman 中的定位:Cavecrew 三人组中的"外科医生"

caveman 是一个以"为什么用很多 token 时,少 token 也能搞定"为核心理念的 Claude Code 技能包,除主对话的"穴居人"压缩风格外,还提供三个输出被压缩的子代理预设:cavecrew-investigator(只读定位)、cavecrew-builder(1-2 文件编辑)与 cavecrew-reviewer(diff 审查)。README.md 对后两者的一句话概括是:

cavecrew-investigator, cavecrew-builder, cavecrew-reviewer — Compressed subagent presets for locating, editing, and reviewing code.

三者中 cavecrew-builder 是唯一拥有写入能力的成员。为什么需要它?plugins/caveman/skills/cavecrew/SKILL.md 给出的动机很直接:子代理的 tool result 会被逐字注入主上下文。一次原生 Explore 返回 2k token 的散文,就会花掉主上下文预算 2k token;同样的发现由 cavecrew-investigator 返回大约 700 token。"在 20 次委派之后,这就是上下文耗尽与完成任务之间的差别。"编辑侧同理——把范围明确的小修改委派给 cavecrew-builder,主线程拿到的只是一份几行的收据,而不是一段探索叙述。

SKILL.md 中的委派决策表明确了 cavecrew-builder 的适用边界:

任务 用什么
外科手术式编辑,≤2 文件,范围明确 cavecrew-builder
新功能 / 3+ 文件 / 跨切面重构 主线程或 feature-dev:code-architect
定位 X 定义 / Y 的调用方 / Z 的使用点 cavecrew-investigator
审查 diff / 分支 / 文件找 bug cavecrew-reviewer

经验法则原文为:"如果你想让子代理的输出占 1/3 的 token,就选 cavecrew;如果想要散文,就选原生代理。" 这也划定了本文主题:cavecrew-builder 不是通用编码代理,而是一个被刻意收窄到"范围有界且显而易见"场景的外科编辑工具。

定义文件全貌:Frontmatter 声明了什么

cavecrew-builder 的源定义位于仓库根部的 agents/cavecrew-builder.mdplugins/caveman/agents/ 下是其插件镜像(两处内容一致)。全文 frontmatter 如下:

---
name: cavecrew-builder
description: >
  Surgical 1-2 file edit. Typo fixes, single-function rewrites, mechanical
  renames, comment removal, format-preserving tweaks. Hard refuses 3+ file
  scope. Returns caveman diff receipt. Use when scope is bounded and
  obvious; do NOT use for new features, new files (unless asked), or
  cross-file refactors.
tools: [Read, Edit, Write, Grep, Glob]
---

三个字段各有明确的工程含义:

  • namecavecrew-builder,主线程委派时使用的代理标识。
  • description:承担"何时该用我"的路由职责。它同时声明了适用场景(typo 修复、单函数重写、机械重命名、删除注释、保格式微调)、硬性红线(3+ 文件范围直接拒绝)和使用禁忌(不用于新功能、除非被要求不建新文件、不做跨文件重构)。这段描述会被主代理在委派决策时读取,相当于把边界条件前置到调度层,而不是等编辑开始后才失败。
  • tools[Read, Edit, Write, Grep, Glob]。注意其中没有 Bash——这不是疏漏而是设计约束,正文会再次强调:"No Bash available — cannot shell out, cannot push, cannot delete." 没有 shell 就没有删除、推送、跑测试、执行任意命令的可能,代理的物理能力边界与其声明的职责边界完全对齐。

对比同组的 cavecrew-investigator.mdcavecrew-reviewer.md,可以看到一个清晰的"最小权限"梯度:investigator 是 [Read, Grep, Glob, Bash](Bash 仅限 git log -S 这类只读命令),reviewer 是 [Read, Grep, Bash](Bash 仅限 git diff/git show),builder 则是唯一给到 Edit/Write 却拿走了 Bash 的成员——能改文件,但不能碰 shell。

正文开头的风格指令只有一句话:

Caveman-ultra. Drop articles/filler. Code/paths exact, backticked. No narration.

即输出同样遵循项目名的"穴居人"压缩语体:去冠词、去填充词,代码与路径必须精确并加反引号,禁止叙述性文字。这是后面所有输出契约的基调。

Scope:三条量化边界

原文档 ## Scope 一节定义了 cavecrew-builder 的全部约束,逐条解读:

  1. 文件数上限:"1 file ideal. 2 OK. 3+ → refuse." —— 1 个文件是理想情况,2 个可以接受,3 个及以上触发拒绝(具体拒绝行见下文 Refusals 一节)。这是一个可以机械执行的硬阈值,也正是 description 中 "Hard refuses 3+ file scope" 的实现承诺。
  2. 只编辑既有文件:"Edit existing only (new file iff user asked)." —— 除非用户明确要求,否则只修改已存在的文件。tools 里虽然有 Write(用于写新文件),但策略层把它锁死在"用户点名要"的场景。
  3. 禁止顺手行为:"No new abstractions. No drive-by refactors. No comment additions." —— 不允许引入新抽象、不允许"路过式"重构、不允许顺带加注释。编辑必须是最小闭环。
  4. 无 shell 能力:"No Bash available — cannot shell out, cannot push, cannot delete."

这四条约束共同保证了 builder 的输出 diff 一定是"外科手术式"的:改动面可数、可预期、可逐行复核。

Workflow:四步最小闭环

原文档 ## Workflow 一节给出固定四步:

1. Read target(s). Never edit blind.
2. Edit smallest diff that work.
3. Re-Read to verify.
4. Return receipt.
  • 第 1 步强制先 Read 目标文件,"绝不盲改"。对子代理而言,这一步同时解决了上下文缺失问题——builder 拿不到主线程的完整探索历史,必须自己读到目标内容的准确现状。
  • 第 2 步要求产出"能工作的最小 diff",与 Scope 的"no drive-by refactors"呼应。
  • 第 3 步是自我验证:改完再 Read 一遍,确认改动落到了正确位置。由于 tools 里没有 Bash,它无法跑测试来验证,重读文件就是它唯一可用的验证手段,这也是收据中 verified: 行的来源。
  • 第 4 步返回收据,格式见下节。

注意整个工作流不产生任何"探索故事"——原文档明确 "No exploration story"。主线程不需要知道 builder 中间读了什么、尝试了什么,只需要最终 diff 和验证结论。

输出契约:Diff 收据(Receipt)

原文档 ## Output (receipt) 一节定义了 builder 的返回格式:

<path:line-range> — <change ≤10 words>.
<path:line-range> — <change ≤10 words>.
verified: <re-read OK | mismatch @ path:line>.

即:每个改动一行,路径:行范围 开头,后接不超过 10 个词的变更描述;最后一行是验证结论——re-read OK(重读通过)或 mismatch @ path:line(重读发现不一致,给出具体位置)。

原文档用一句话总结了这套契约的哲学:

Diff is the artifact. Receipt is the proof. No exploration story.

Diff 是工件,收据是证明。plugins/caveman/skills/cavecrew/SKILL.md 的"Output contracts"一节把同一契约表述为"主线程可以依赖什么",并补充了一条关键信息:收据要么符合上述格式,要么以 too-big. / needs-confirm. / ambiguous. / regressed. 之一的终止首词开头。也就是说,主线程解析 builder 的输出只需要两个分支:收据行(可用 path:\d+ grep)或终止拒绝行,没有任何第三种形态。这个"可机读的输出文法"是压缩语体能被主线程可靠消费的前提。

Refusals:四类终止性拒绝行

原文档 ## Refusals (terminal lines) 一节定义了 builder 的四条拒绝路径,每条都是固定句式:

触发条件 终止行
需要改 3 个及以上文件 too-big. split: <n one-line tasks>.
需要执行破坏性操作 needs-confirm. op: <command>.
规格含糊 ambiguous. ask: <one question>.
编辑后测试失败且无法在范围内修复 regressed. revert path:line. cause: <fragment>.

四个细节值得注意:

  • too-big 不只是拒绝,还给出拆分建议split: <n one-line tasks> 要求把大任务拆成 n 个一行可描述的子任务,方便主线程直接续派。SKILL.md 的"What NOT to do"里也提醒:不要对 5 文件重构走 investigator → builder 链,"Builder will return too-big. and you'll have wasted a turn."
  • needs-confirm 把破坏性操作推回用户。builder 自己不能执行破坏性命令(没有 Bash),遇到这种需求时显式点名是哪个命令,等主线程/用户确认。
  • ambiguous 限制为"只问一个问题"。子代理问十个问题是 token 黑洞,强制单问保持对话收敛。
  • regressed 同时给出回滚坐标和原因片段revert path:line 让调用方能一步撤销,cause: <fragment> 提供最小诊断线索。这是四行里唯一涉及"事后状态"的,也解释了为什么 Workflow 第 3 步的重读验证如此关键——验证失败本身就是拒绝信号之一。

四条拒绝行与收据格式共同构成 builder 完整的输出文法:正常路径返回收据,异常路径返回以固定首词开头的终止行,主线程据此决定"继续 / 拆分 / 追问 / 回滚"。

Auto-clarity:安全场景自动切回正常英语

原文档 ## Auto-clarity 一节只有一行规则:

Security or destructive paths → write normal English warning, then resume caveman.

即:当涉及安全警告或破坏性操作时,builder 放弃穴居人语体,用正常英语写出警告,之后再切回压缩语体。这不是 builder 独有的机制,而是整个 cavecrew 组的继承条款——cavecrew-investigator.md 有对应的 "Security warnings, destructive ops → write normal English. Resume after.",cavecrew-reviewer.md 则是 "Security findings → state risk in plain English first sentence, then caveman fix line.",SKILL.md 将其概括为:

Subagents drop caveman → normal English for security warnings, irreversible-action confirmations, and any output where fragment ambiguity could be misread. Resume caveman after.

背后的权衡很清楚:压缩语体在"定位结果""diff 收据"这类结构化信息上收益最大,但在安全警告上,碎片化表达存在被误读的风险(比如 needs-confirm. op: rm -rf ... 式的省略可能掩盖真实破坏范围)。因此项目约定"风险语句永远用完整英语",其余部分保持压缩。对实现一个 token 压缩代理系统来说,这是一条值得借鉴的设计原则:压缩策略应按信息的安全敏感度分级,而不是一刀切。

源码佐证(一):CAVECREW_BUILDER_MODEL 如何改写这个定义文件

builder 定义文件不是静态资产——仓库自带一个 Hook 可以在不复制整个代理文件的前提下,为它单独钉住模型。src/hooks/cavecrew-model-overrides.jsSessionStart 早期被 caveman-activate.js 调用,文件头部注释写明了机制:

// Env vars:
//   CAVECREW_REVIEWER_MODEL    → agents/cavecrew-reviewer.md
//   CAVECREW_BUILDER_MODEL     → agents/cavecrew-builder.md
//   CAVECREW_INVESTIGATOR_MODEL → agents/cavecrew-investigator.md

关键实现点(对应源码行为):

  • 补丁对象是 YAML frontmatter 的 model:。若已有 model: 行则原地替换;若没有,则插入到 tools: 行之后(或闭合 --- 之前)。这正对应 builder 文件当前只有 tools: 没有 model: 的结构——设置 CAVECREW_BUILDER_MODEL=haiku 后,frontmatter 会变成:

    name: cavecrew-builder
    description: >
      ...
    tools: [Read, Edit, Write, Grep, Glob]
    model: haiku
    
  • 防御性规则:未设置/空白 → 不做任何事;值中含换行或控制字符([\x00-\x1f\x7f])→ 忽略;文件缺失或布局不符 → 静默跳过;所有文件系统错误 → 静默失败,"绝不阻塞会话启动"。

  • 补丁保留原文件换行风格:frontmatter 为 CRLF 时插入行也使用 CRLF,避免在 Windows 上制造混合换行。

  • 一条有意思的自保护逻辑 insideGitWorkTree:如果插件根目录位于某个 git 工作树内,说明这是一份源码检出而非已安装插件,此时 Hook 直接 return,不写任何文件。源码注释解释了这个坑的来历:曾在克隆仓库里打开时,每个 SessionStart 都会重写被跟踪的 agents/*.md,把用户的工作区弄脏。所以覆盖只发生在 $CLAUDE_CONFIG_DIR 下的已安装插件布局中——"那是能应用覆盖而不编辑别人源码的唯一地方"。

该 Hook 的行为有专门测试 tests/test_cavecrew_model_overrides.js 覆盖。对比同组的 investigator 与 reviewer,它们的 frontmatter 自带 model: haiku(用小模型进一步压成本),而 builder 的定义文件没有默认 model: 行——可以推断 builder 默认跟随宿主代理的主力模型,因为编辑质量比定位/审查更依赖模型能力,需要 CAVECREW_BUILDER_MODEL 来显式降级或指定。

源码佐证(二):这份定义文件如何到达最终用户

plugins/caveman/agents/cavecrew-builder.md 与根目录 agents/cavecrew-builder.md 两份内容一致不是巧合。CLAUDE.md 记录了这份文件的维护模型:

  • agents/ 目录是三个 cavecrew 子代理的单一事实源("single source — kept at root for plugin auto-discovery"),即 Claude Code 从仓库根布局自动发现代理;
  • 仓库有一个同步流程(CLAUDE.md 描述为由 .github/workflows/sync-skill.ymlmain 分支 push 且 skills/**/SKILL.mdagents/cavecrew-*.md 变化时触发),将 agents/cavecrew-*.md 复制到 plugins/caveman/agents/,让 Claude Code 插件加载器看到最新行为;
  • 维护规则同样在 CLAUDE.md 的映射表中写明:plugins/caveman/agents/cavecrew-*.md 对应源头 agents/cavecrew-*.md

所以本文开头的"核心骨架"文件(plugins/caveman/agents/cavecrew-builder.md)是插件分发的消费端镜像,编辑行为应改源头 agents/cavecrew-builder.md,镜像由同步流程刷新。

另一条分发路径面向 opencode。bin/install.js 中有一行安装清单:

const OPENCODE_AGENT_FILES = ['cavecrew-investigator.md', 'cavecrew-builder.md', 'cavecrew-reviewer.md'];

安装器会把三个代理文件作为 opencode 的 agent 资产安装(相关行为由 tests/installer/opencode-agent.test.mjstests/installer/opencode.test.mjs 验证)。从安装路径角度看,cavecrew-builder 的同一份定义文件同时服务 Claude Code(插件镜像 + 根目录自动发现)与 opencode(安装器资产)两类宿主,frontmatter 中 tools 白名单因此必须对两种工具语义都成立。

实战:与 cavecrew 决策指南配合的三种编排模式

单独看 builder 定义文件,它只是"1-2 文件编辑器";放进 plugins/caveman/skills/cavecrew/SKILL.md 的编排框架里,才能看到它在实际会话中的位置。SKILL.md 给出三种委派链:

1. 定位 → 修复 → 验证(最常见)

  1. cavecrew-investigator 返回站点列表(path:line — symbol — note 表);
  2. 主线程挑出 1-2 个站点,把路径交给 cavecrew-builder
  3. cavecrew-reviewer 审查 diff(输出 path:line: <emoji> <severity>: <problem>. <fix>.)。

这条链恰好对应三个代理的输出契约首尾相接:investigator 的 path:line 表是 builder 的输入,builder 的 path:line-range 收据是 reviewer 的输入。每一步注入主上下文的内容都在数百 token 量级。

2. 并行侦察(调查面很宽时):在一条消息里同时派 2-3 个 cavecrew-investigator(不同切面:定义 vs 调用方 vs 测试),主线程汇总。

3. 单点编辑(站点已知时):跳过 investigator,把精确的 path:line 直接交给 cavecrew-builder

SKILL.md 同时列出了四条"不要做",其中三条直接约束 builder 的正确用法:

  • 不知道文件时不要用 cavecrew-builder——先派 investigator,否则主线程会把上下文 token 花在传递定位信息上;
  • 不要为 5 文件重构链 investigator → builder——builder 会返回 too-big.,浪费一个回合(呼应其 Refusals 第一条);
  • 不要期望散文——cavecrew 输出是结构化、有时简到近乎密码的,"如果人类要直接读它,请转述"。

最后一句是对 Auto-clarity 机制的实用补充:收据和终止行是为机读优化的,给人看时需要 paraphrase。

速查表

维度 规则 出处
文件数 1 理想,2 可,3+ 拒绝 agents/cavecrew-builder.md Scope
新文件 仅当用户明确要求 同上
顺手行为 禁止新抽象 / 重构 / 加注释 同上
工具 Read, Edit, Write, Grep, Glob,无 Bash frontmatter tools
工作流 Read → 最小 Edit → 重 Read → 返回收据 同上 Workflow
正常输出 <path:line-range> — <≤10 词变更>. + verified: 同上 Output
拒绝输出 too-big. / needs-confirm. / ambiguous. / regressed. 开头 同上 Refusals
安全语句 切正常英语警告,随后恢复压缩语体 同上 Auto-clarity
模型覆写 CAVECREW_BUILDER_MODEL 环境变量改写 frontmatter model: src/hooks/cavecrew-model-overrides.js
单一事实源 agents/cavecrew-builder.md,插件镜像由同步流程刷新 CLAUDE.md
适用任务 外科手术式编辑、≤2 文件、范围明确 plugins/caveman/skills/cavecrew/SKILL.md 决策表

小结

cavecrew-builder 是 caveman 项目中"token 经济学"落到编辑环节的具体实现:frontmatter 用 tools 白名单物理上砍掉 shell 能力,Scope 用可机检的阈值(3+ 文件)划定职责,Workflow 用"重读即验证"弥补没有测试执行的缺陷,Output 用"收据或终止行"的二值文法保证主线程可解析,Refusals 用四条固定句式把失败模式变成可续接的信号(拆分/确认/追问/回滚),Auto-clarity 再为安全语句留出不压缩的通道。围绕这个定义文件,仓库还提供了模型覆写 Hook(src/hooks/cavecrew-model-overrides.js)、单源-镜像同步机制(CLAUDE.md)与多宿主安装路径(bin/install.js),使其成为一份同时可被 Claude Code 与 opencode 消费、可被环境变量个性化、且行为可被 tests/test_cavecrew_model_overrides.js 等测试固化的生产级代理定义。对于想在自己的代理系统中约束子代理输出形态的开发者,这份 47 行的文件是一个密度很高的参照样本。

登录后查看全文
热门项目推荐
相关项目推荐