caveman cavecrew-builder 子代理设计详解:1-2 文件外科编辑、Diff 收据与拒绝协议
本篇技术文章以 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.md,plugins/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]
---
三个字段各有明确的工程含义:
name:cavecrew-builder,主线程委派时使用的代理标识。description:承担"何时该用我"的路由职责。它同时声明了适用场景(typo 修复、单函数重写、机械重命名、删除注释、保格式微调)、硬性红线(3+ 文件范围直接拒绝)和使用禁忌(不用于新功能、除非被要求不建新文件、不做跨文件重构)。这段描述会被主代理在委派决策时读取,相当于把边界条件前置到调度层,而不是等编辑开始后才失败。tools:[Read, Edit, Write, Grep, Glob]。注意其中没有Bash——这不是疏漏而是设计约束,正文会再次强调:"NoBashavailable — cannot shell out, cannot push, cannot delete." 没有 shell 就没有删除、推送、跑测试、执行任意命令的可能,代理的物理能力边界与其声明的职责边界完全对齐。
对比同组的 cavecrew-investigator.md 与 cavecrew-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 file ideal. 2 OK. 3+ → refuse." —— 1 个文件是理想情况,2 个可以接受,3 个及以上触发拒绝(具体拒绝行见下文 Refusals 一节)。这是一个可以机械执行的硬阈值,也正是 description 中 "Hard refuses 3+ file scope" 的实现承诺。
- 只编辑既有文件:"Edit existing only (new file iff user asked)." —— 除非用户明确要求,否则只修改已存在的文件。
tools里虽然有Write(用于写新文件),但策略层把它锁死在"用户点名要"的场景。 - 禁止顺手行为:"No new abstractions. No drive-by refactors. No comment additions." —— 不允许引入新抽象、不允许"路过式"重构、不允许顺带加注释。编辑必须是最小闭环。
- 无 shell 能力:"No
Bashavailable — 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 returntoo-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.js 在 SessionStart 早期被 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.yml在main分支 push 且skills/**/SKILL.md或agents/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.mjs 与 tests/installer/opencode.test.mjs 验证)。从安装路径角度看,cavecrew-builder 的同一份定义文件同时服务 Claude Code(插件镜像 + 根目录自动发现)与 opencode(安装器资产)两类宿主,frontmatter 中 tools 白名单因此必须对两种工具语义都成立。
实战:与 cavecrew 决策指南配合的三种编排模式
单独看 builder 定义文件,它只是"1-2 文件编辑器";放进 plugins/caveman/skills/cavecrew/SKILL.md 的编排框架里,才能看到它在实际会话中的位置。SKILL.md 给出三种委派链:
1. 定位 → 修复 → 验证(最常见)
cavecrew-investigator返回站点列表(path:line — symbol — note表);- 主线程挑出 1-2 个站点,把路径交给
cavecrew-builder; 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 行的文件是一个密度很高的参照样本。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00