Claude Code 成本优先的 Subagent 与 Workflow 调度实践

基于 Claude Code 2.1.282,梳理多代理能力边界、任务等级、并发预算和 Fable 使用配额

第 06 篇发布于 更新于

返回博客

多代理系统最昂贵的错误,通常不是某个 Agent 回答错了,而是主 Agent 在没有收益的地方复制上下文、增加启动,并让昂贵模型处理本可由便宜模型完成的任务。

本文以本机 Claude Code 2.1.282 为基线(初稿写于 2.1.260,2026-09-07 按 2.1.261–2.1.263、2026-09-10 按 2.1.265–2.1.267、2026-09-14 按 2.1.268–2.1.270、2026-09-23 按 2.1.271–2.1.280 的变更和当前文档逐条复核,2026-09-25 按 2.1.281–2.1.282 的变更复核),研究 Agent、Fork、Workflow、Agent Team 与 Agent SDK。目标不是“尽量多调 Agent”,而是让每次上下文创建都有必要性、预算和停止条件。

2.1.260 修复了 model: fable Agent 忽略 ANTHROPIC_DEFAULT_FABLE_MODEL 中 [1m] 标签的问题,也修复了 Fable 5.1 在工具结果之后的上下文未进入 Prompt Cache。前一项只针对该环境变量 pin,不能据此反推所有 2.1.259 会话都只用了 200K 上下文。

完整的英文 CLAUDE.md、Agent 定义和 Workflow Authoring 配置已拆到《Claude Code 多代理调度 Prompt 与 Agent 配置模板库》。日常直接发送的 Workflow、Subagent、Agent Team 与工程实践片段,集中保存在《我的 AI Agent Prompt Tips》。

一、先分清五种执行机制

机制上下文与协作方式适合场景成本风险
主 Agent使用当前会话上下文小任务、强依赖当前讨论长会话持续携带历史上下文
Subagent独立上下文,结果返回主 Agent有界搜索、实现、审查、验证委派过细会重复加载项目背景
Fork继承完整父会话,再独立继续必须理解完整讨论的分支失去输入隔离,并行分支放大总量
WorkflowJavaScript 编排 Agent可重复、依赖明确的多阶段任务fan-out、重跑和循环迅速放大 Token
Agent Team独立会话持续互相通信需要辩论与协作的长任务官方数据:plan mode 下约为单会话 7 倍

General-purpose 和自定义 Subagent 不继承主对话,但会读取适用的 CLAUDE.md 和 Git 状态,除非定义设置 omitClaudeMd: true(2.1.271+;managed policy 文件与 Git 状态仍加载)。Skill 只在自定义定义的 skills: 字段列出时才会预加载;官方写明内置类型(含 general-purpose)不预加载任何 skill。内置 Explore 与 Plan 为降低成本,连 CLAUDE.md 和父会话 Git 状态也跳过。

Subagent 默认与主 Agent 共用工作目录。只有显式使用 worktree 隔离时,文件修改才真正分开。

Fork 会复用父会话 Prompt Cache。任务确实需要完整上下文时,它可能比重新向普通 Subagent 解释背景更便宜;不需要完整上下文时,它仍然复制了过多信息。

二、Claude Code 原生允许控制什么

普通 Agent

主 Agent 可以在每次调用中指定 subagent_type、prompt、description 和 model,并按条件设置名称、后台运行或 worktree 隔离。

在 2.1.280 中,模型解析顺序是:本次调用的 model、Agent 定义的 model、CLAUDE_CODE_SUBAGENT_MODEL、主会话模型。v2.1.251 之前环境变量优先,跨版本模板不能省略版本检查。CLAUDE_CODE_SUBAGENT_MODEL 因此只是第 3 位的默认值:本机 Hook 强制每次调用带模型、九个角色定义都固定模型,它对这些路径没有作用;它唯一能改变的是不经 Agent 工具、以 forked subagent 运行的内置 skill 所用的模型(文档明确写了 /code-review 这样运行;/simplify、/security-review 是否同样 fork 文档未写,要靠 /tasks 实测)。2026-09-14 评估后保持不设,理由见第十二节。

若启用 v2.1.257 新增的 CLAUDE_CODE_SUBAGENT_MODEL_FORCE,Claude Code 会忽略定义与逐次模型选择。需要混合模型路由时必须关闭它,并从 Agent 工具的返回结果核对实际模型。

从 v2.1.198 起,内置 Explore 不再固定使用 Haiku,而是继承主会话模型;在 Claude API 上最多到 Opus。若要保持低成本,应定义同名、固定 model: haiku 的自定义 Explore。

effort 仍不是普通 Agent 的逐次调用参数,应写入 Agent 定义、--agents JSON 或 SDK AgentDefinition。

普通 Agent 没有独立累计 Token 上限,也没有整段墙钟超时。API_TIMEOUT_MS 约束单次 API 请求,CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS 只检测流停滞,都不是整个 Subagent 的总时间。

Dynamic Workflow

Workflow 中的 agent() 可以逐 Agent 指定 model、effort 和输出 schema。model 与 schema 在 workflows 文档页有据;effort 选项及其"省略则继承会话 effort"的规则只写在 bundled workflow-authoring skill 里。Workflow 原生提供 agent、pipeline、parallel、phase 与日志能力。

Workflow 脚本运行在主上下文外,不能直接访问文件系统、Shell 或任意模块;真正的读写与命令仍由其中的 Agent 完成。

官方运行时默认最多允许 16 个并发 Agent(CPU 少时更低;2.1.269 起可用 CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS 在 1–256 范围内改写,env-vars 与 workflows 文档都已收录:默认最多 16 个,值越高内存占用越大;本机不设)、单个 parallel() 或 pipeline() 最多 4096 个 item、整次运行最多 1000 个 Agent。这些是容量保护,不是合理的成本预算,并发上限还可以由用户自己抬高。另有一条只提示不拦截的"Large workflow"警告:一次运行调度超过 25 个 Agent,或预计 token 超过 150 万时触发;选了 workflowSizeGuideline 后该档的 Agent 数会替换 25 这个阈值。Workflow Agent 与 Subagent 的 prompt cache 默认只保 5 分钟,subagentPromptCacheTtl: "1h" 可延长到一小时,代价是一小时缓存写入按更高价计费。

workflowSizeGuideline 也只是建议:small 少于 5、medium 少于 10(2.1.271 起,此前为 15)、large 少于 50。大型警告不会暂停或限制运行。显式选定的档位会把这条只提示的 Large workflow 警告阈值换成该档的 Agent 数,所以本机一次运行超过 10 个 Agent 就会看到警告。本机 2026-09-14 起取 medium,真正的上限是第五节的加权启动预算。

Workflow 中间失败后重新启动,可能让失败节点之后已经完成的 Agent 再次运行。因此预算必须按实际 Agent 启动次数计算,不能只数脚本中的静态节点。

Agent SDK

SDK 顶层的 maxBudgetUsd 控制整次 query 的美元预算,也就是主 Agent 和它创建的整棵子树,而不是树中的某个 Subagent。

API 的 task_budget Beta 会给模型一个整段 Agent Loop 的 Token 倒计时,但它是软预算,而且 Claude Platform 明确说明 Claude Code 与 Cowork 界面不支持。不能把它描述为 Claude Code 的单 Subagent 硬上限。

某个 Worker 若必须拥有独立美元预算或墙钟超时,可把它拆成独立 SDK query,由该 query 的 maxBudgetUsd 约束估算成本,并由宿主进程计时、中断。代价是它不再是主会话里的普通 Subagent。

三、能力边界表

控制项普通 AgentWorkflow agent()Agent SDK
逐次选择模型支持支持支持
逐次选择 effort不支持,写入定义支持通过定义或 query 配置
单 Agent Token 预算不支持不支持无 CC 硬上限;API Beta 仅有软预算
整棵调用树美元预算不支持不支持maxBudgetUsd
单 Agent 墙钟超时不支持不支持宿主计时并中断
独立 Git 工作区worktree由 Agent 隔离方式决定由宿主与定义决定

Claude Code 原生支持模型和 effort 分层,但不能把 Prompt 里的“1 小时”或“10 万 Token”自动变成硬限制。唯一接近的是“+500k”这类 +Nk Token 指令:它给本回合设定一个输出 Token 目标,bundled workflow-authoring skill 称之为 Workflow agent() 调用的硬上限(花满后再调用 agent() 会抛错),但这个额度由主循环与所有 Workflow 共享,不按 Agent 分配,而且只写在那份 bundled skill 里。

四、模型角色分层

角色默认模型 / effort允许集合典型任务
专用主协调 profileOpus / high固定拆解、调度、证据整合与验收
ExploreHaikuhaiku, sonnet文件定位、窄搜索、证据清单
plannerSonnet / highsonnet, opus有界计划、依赖分析;跨模块架构升 Opus
implementerOpus / highopus, sonnet常规生产与测试实现;可精确描述的机械改动降 Sonnet
qaSonnet / highsonnet, opus构建、测试、复现、浏览器验证
reviewerSonnet / highsonnet, opus常规独立审查;权限、数据、并发、迁移、公共契约升 Opus
reviewer-fableFable / lowfableSonnet 判断不够时的只读审查,每任务成本与 Sonnet/high 相当
critical-implementerFable / highfable关键复杂实现
critical-reviewerFable / highfable安全、并发、迁移与架构审查

默认值是起点不是上限。每次调用可以在允许集合内升降档,Hook 只拒绝集合之外的模型。升档顺序来自 Claude Code 官方的模型选择指引:"它是没尽力,还是不够懂?"没尽力(漏读文件、没跑测试、没复核)就升 effort 或换更清晰的 prompt 重跑;不够懂(细微 bug、陌生领域、架构决策)才换更强的模型。判断成本要按每个完成的任务算,需要多跑一轮的便宜 Worker 并不便宜。

规则里只写 haiku、sonnet、opus、fable 别名,由 Claude Code 解析到当前一代,不固定具体版本和价格。当前一代里相邻档位的每 token 单价大约只差 2 倍,真正放大成本的是轮次与上下文长度。Explore 的搜索超出 Haiku 的能力范围时,可在允许集合内改用 Sonnet/low。

这些值是本文模板的角色成本规约,不是 Claude Code 官方最佳值。应通过成功率、返工、输出 Token 和耗时调整具体角色,不能用一个模型覆盖所有任务。

复杂工程会话可显式启动专用 Opus/high coordinator profile 负责拆解与验收,并把委派的 Fable/high 限于一次关键判断。该 profile 不改写全局主会话默认值。

五、任务等级与 Agent 预算信封

预算限制的是一次用户任务的加权启动总数和同时活动的 Workflow 数。启动按 Opus 当量计:每次启动按模型加权,haiku 0.25、sonnet 0.5、opus 1、fable 2.5(按 API 标价与 Opus 5.5 的比值,Opus 5.5 是 2.1.280 起 opus 别名所指,每百万 token 输入 4 美元、输出 20 美元;订阅额度的消耗大致同比);两个角色例外,reviewer-fable(Fable/low)按 1 计,依据是官方"Fable 5.1 在 low 档常与 Opus、Sonnet 单任务成本相当"的说法,两个 critical 角色(Fable/high)按 2.5 计。effort 改变一次启动的 token,但不改变权重。并发不再是预算项,见第六节。

等级适用任务启动预算(Opus 当量)同时活动 Workflow关键席位 Fable 启动数
L0 直接当前上下文可完成的解释或微小编辑000
L1 有界单一、独立、无需交叉验证100
L2 标准一次实现及独立 QA/Review41最多 1
L3 复杂跨模块、高风险或研究后实现61最多 1
L4 特殊大型迁移、全仓审计、性能攻坚8,需用户批准1最多 1

举例:一个 Opus implementer、一个 Sonnet qa、一个 Sonnet reviewer 加五次 Haiku Explore 用掉 L2 的 3.25;三个 Opus 加两个 Sonnet 读取器用掉 L3 的 4;八个 Sonnet finder 的 Workflow 用掉 4。

“启动数”包括普通 Agent、Fork、Workflow agent()、每个 pipeline item、restart、resume、repair、Workflow relaunch 后实际重跑的 Agent,以及 Agent Team 的每个 Teammate。

同一 Agent ID 再运行一次也重新计数。主 Agent 不计入 Worker 数,但其输入、输出与 thinking Token 必须单独观测。

一个用户任务同时最多运行一个 Workflow。任务被拆成多个顺序 Workflow 时,加权启动总数仍按同一个用户任务累计,不能通过拆成两个 Workflow 绕过 L3 的 6 当量总额。

L2 的 4 当量可以覆盖 Opus 实现、Sonnet QA、Sonnet Review 和一次有证据的 repair。没有 repair 时无需把预算用满。

L4 只能由用户在当前对话明确批准。任务困难、运行时间长或 Agent 已失败,都不是主 Agent 自动升级的授权。

六、并发规则

并发不省 token,只改变墙钟:同一批启动无论排队还是同时跑,消耗完全一样;Workflow 里同一次 fan-out 的兄弟 agent 还共享 prompt cache 前缀,Claude Code 会扣住其余 agent,等第一个开始回复再一起放行。所以一个阶段里所有相互独立的启动全部并行,只有依赖前一步结果的阶段才串行;也不要为了填满并发去发明独立工作,每次启动仍需理由。2026-09-14 之前这里写的是"默认串行、按等级限制实时并发",那是把成本杠杆和速度杠杆混在了一起,已废弃。

同一阶段只能选择直接 Agent batch 或 Workflow,不能混合运行。否则 Agent 工具和 Workflow 各自遵守产品上限,却可能形成不可见的合计并发。

产品上限仍然存在:Agent 工具受 CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS(本机 12)约束,Workflow 每次运行最多 16 个并发 agent。候选集合超过这些上限时分批跑,不能静默截断;超过等级的加权预算时应立即失败并返回溢出清单。

CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS 只约束 Agent 工具派生的 Subagent,不约束 Workflow Agent 或 Team,因此不能充当统一并发预算。sub-agents 文档还写明两处漏洞:/subtask 发起的 fork 占槽位但从不被它拦下;resume 一个已完成的 Subagent 不检查上限就占用新槽位,所以 resume 能把并发数推过上限。本机 Hook 对 Fable 目标或解析不到的 agent ID 的 resume 是 deny,其余 resume 只返回 ask,bypass 会话里等于放行。

成本优先的会话不应把 /effort ultracode 设为默认。Ultracode 会使用 xhigh 并为每个实质任务自动设计 Workflow,还会跳过常规 Workflow 批准与大型运行警告;sub-agents 文档明确 ultracode 会话不执行 CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS,也就是最后一道数字上限一起失效。

七、Fable 5.1 使用闸门

委派的 Fable Worker 分两类,预算方式不同。

reviewer-fable 用 Fable/low 做只读审查。官方 Fable 5.1 指南写明,low 下的 Fable 在每任务成本上常与更高 effort 的 Sonnet 或 Opus 相当且得分更高,凡是原本要用小模型跑高 effort 的场景都应把它纳入对照。所以它是普通启动,从 L1 起可用,计入等级总数,不占关键席位;因为 low 下 Fable 较少主动检索,prompt 要求它先读再下结论。

关键席位是 critical-implementer 与 critical-reviewer,Fable/high,一个用户任务最多一次,从 L2 起可用(一次实现加一次独立审查本来就是 L2,其中的审查可以是关键的那一次),任何 Fable Worker 同时最多一个在跑。使用关键席位至少满足一个条件:

  • 安全、权限或隐私不变量;
  • 并发、事务或一致性正确性;
  • 不可逆数据迁移或高影响发布;
  • 关键架构边界;
  • 对应的常规角色已完成一次有证据的尝试,但明确问题仍未解决。

关键角色从 high 起步,这与 Anthropic 对 Fable 5.1 的建议一致:先用 high,再以真实 eval 比较 low、medium、xhigh 与 max;只有 eval 证明 high 仍有余量时才升到 xhigh。implementer 的 Opus/high 比模型默认高一档:2.1.280 起 opus 指向 Opus 5.5,它默认 medium;model-config 写明其余支持 effort 的模型默认都是 high,只有 Opus 4.7 默认 xhigh,此外 xhigh 作为默认只出现在 ultracode 下。定义里的 effort 优先于会话档位,所以 implementer.md 固定的 high 在 Opus 5.5 上照样生效。返工或验证失败时再升档。

Fable 5.1 带安全分类器,可能以 refusal 结束响应。官方说明在源码中查找漏洞是允许的,误拒主要来自"能否编译"式的提问、冷门语言和工具输出里的 base64。Claude Code 本身有分类器触发的自动回退:model-config 写明 Fable 5.1 与 Opus 5.5 被 biology 分类器标记时重跑 Opus 5,被 cybersecurity 标记时重跑 Opus 4.8,并在 transcript 里提示;Opus 5 自己也带分类器,cybersecurity 命中同样重跑 Opus 4.8,biology 命中则直接以 refusal 结束、没有回退模型。本机 switchModelsOnFlag: false 把自动回退变成交互会话里的暂停选择、-p 下的直接报错,文档也没有写这条回退是否作用于 Subagent。所以委派的 Fable Worker 返回 refusal 时仍按本地规则处理:不算"一次有证据的常规角色失败",直接改用 Opus/xhigh 重做,且不再消耗 Fable 配额。2.1.280 起这次重做跑在 Opus 5.5 上,它同样可能被分类器标记:cybersecurity 回退到 Opus 4.8,biology 转到 Opus 5,之后的 biology 请求在 Opus 5 上都会 refusal;此前重做跑在 Opus 5 上时也会被标记,所以规则不变。biology 类 refusal 换到 Opus 5 只会再得到一次 refusal,这时要改写任务而不是换模型。

全局主会话默认自 2026-09-25 起是 opus 别名所指的 Opus 5.5(modelSettings 固定 high);Fable 5.1 按会话用 /model fable 切换,它的 per-model 档位保存为 xhigh,这是用户有意的选择:需要 Fable 的会话要的就是判断质量。没有 effort 字段的 Worker 继承会话当时的档位,无论它是多少。档位越低,Fable 越可能直接凭记忆回答并减少检索,因此应继续用真实工作负载评估效果。

Fable 5.1 在长工具链中可能减少可见进度更新。Prompt 可以明确要求启动说明、简短阶段进度和独立的最终 recap,同时写清完成任务与范围边界。

主 Agent 可在后台 Subagent 运行时处理其他独立工作,以降低等待时间。这只是可选优化,不能突破任务的加权启动预算,也不应为了“并行”强拆任务。

委派的 Fable Worker 不得用于 Explore、逐文件 fan-out、日志归纳、常规实现、构建、浏览器 QA、格式化、文档整理或普通 Review。

委派的 Fable Worker 不能作为 Workflow 第一阶段,不能放进 parallel() 或 pipeline()。它必须在非 Fable 的常规角色结果 fan-in 后,接收一份精简证据包再串行运行。

一个用户任务最多启动一个关键席位的 Fable Worker,任何 Fable Worker 的实时并发永远为 1。

百分比是结果,不是目标。不能为了降低委派 Fable Worker 占比而创建无用的 Haiku/Sonnet Agent。

委派的 Fable Worker 不得自动 restart、resume 或 repair。如果一次调用仍不足,应停止当前预算信封,向用户说明已有证据和新增调用理由,由用户决定是否开启例外。

八、软规则与硬门禁

四类边界不能混为一谈:

边界负责内容不能替代
Claude Code 容量限制Workflow 最大并发、item 和 Agent 数个人成本预算
Prompt 策略等级、账本、范围、完成条件与汇报节奏硬阻断
permissions 与 Hooks工具许可和匹配调用的拒绝Workflow 内部模型治理
Workflow 治理经审查的依赖图与人工批准更强宿主的整棵调用树硬预算

主协调 Prompt 应先声明任务等级、预算账本和模型路由。它可以要求完成任务、限定范围和汇报节奏,但仍是行为约束。

当自定义 Agent 通过 claude --agent coordinator 作为主线程运行时,tools: Agent(worker, reviewer) 可以在工具层限制它能创建的 Agent 类型。不给主 Agent Edit、Write 和 Shell,就能强制“只统筹不实现”。

Worker 定义不提供 Agent 工具,再配合派生深度 1,可以禁止嵌套 Subagent。实测的 Agent PreToolUse Hook 要求显式 type/model,拒绝模型不匹配以及 Agent 类型不是已批准关键角色的 Fable。L3/L4 用户批准仍由 Prompt 与人工治理,不是该 Hook 的检查项。

2.1.282 的 Agent 工具入参仍没有 resume(本机 Agent Team 关闭的会话里,工具 schema 只有 subagent_type、prompt、description、model 与 isolation,2026-09-25 在 2.1.282 会话中再次确认;文档另有 name 参数,用于给 Subagent 命名以便按名 resume,开启 Agent Team 时带 name 的调用会变成 Teammate)。续跑一个已完成的 Subagent 走 SendMessage,它会在后台自动 resume 且不再经过 Agent 调用。因此 Hook 必须同时匹配 SendMessage。该输入只带 to 字段,官方写明它既可以是名称也可以是 agent ID,看不到目标模型。本机的做法是:目标名称含 critical- 或 fable 时 deny,发往 main 放行;纯 ID 则到会话目录的 subagents/agent-<id>.meta.json 读取该 Agent 的 model 与 agentType,是 Fable 就 deny,解析不到也 deny(fail closed),其余 ask。官方 hooks-guide 保证:"PreToolUse hooks fire before any permission-mode check, in every permission mode, including dontAsk. A hook that returns permissionDecision: deny blocks the tool even in bypassPermissions mode or with --dangerously-skip-permissions." ask 在 bypass 下的行为文档没有正面写;本机实测它会被直接放行、不弹窗。所以在 bypass 会话里只有 deny 有效,关键路径一律用 deny。

Fork 是另一条绕行路径:subagent_type: fork 会忽略 model 参数并直接运行在主会话模型上。主会话默认是 Fable 时,一个带 model: opus 的 fork 能通过模型校验却实际消耗 Fable。本机 Hook 对 fork 直接 deny,需要完整上下文时由用户临时放开。

permissionMode 也不是硬边界。官方文档写明:父会话使用 auto 时,Subagent 继承 auto,其定义中的 permissionMode 被忽略;父会话为 bypassPermissions 或 acceptEdits 时同样不可覆盖。父会话为 default、dontAsk 或 plan 时定义才生效,但自 2.1.267 起 Subagent 声明 bypassPermissions 也会被改回父会话模式。本机 defaultMode 正是 auto,因此 reviewer、critical-reviewer 与 qa 的只读约束实际只来自工具列表和 Prompt,凡是保留 PowerShell 的角色都能写文件。

Policy Hook 收到畸形 JSON 时,必须直接向 stderr 写简短消息并精确地 exit 2,才能 fail closed。PreToolUse 的 exit 1 不会阻断。命令 Hook 的 command + args exec 形式自 2.1.139 起可用,hooks 文档对它不带版本限定。PreToolUse 除 allow、deny、ask 之外还有第四种结果 defer,多个 Hook 冲突时优先级是 deny > defer > ask > allow;不过 defer 只在 -p 非交互模式下生效,交互会话会记一条警告并忽略它,对本机这种交互 bypass 会话没有意义。另一条容易忽略的规则:ask 与 allow 的 permissionDecisionReason 只显示给用户,不给 Claude;要让 Claude 在放行后看到的说明必须放进 additionalContext,只有 deny 的 reason 会进入模型上下文。

Workflow 的 agent() 在没有指定 model 时运行在主会话模型上(workflows 文档原文:"When nothing else assigns one, the agent runs on your session's model");effort 按 bundled workflow-authoring skill 的说明同样继承会话值;主会话是 Fable/xhigh 时,一个 fan-out 就会把整批 Agent 放到最贵的档位。本机 Hook 因此读取 tool_input.script(或 scriptPath、按 name 解析到的 Saved Workflow 文件,查找范围是工作目录到仓库根目录(第一个含 .git 的祖先目录)之间的各级 .claude/workflows,再到 CLAUDE_CONFIG_DIR(未设置时为 ~/.claude)下的 workflows,与 workflows 文档写明的加载范围一致;插件 Workflow 的脚本在插件目录的 workflows/ 下,Hook 不去那里找,其带冒号的命名空间名称也过不了名称校验),先做一遍词法标记,把注释、字符串和模板字面量的内容剔出代码(模板里的 ${} 表达式仍算代码),正则字面量按前一个有效字符判定,再逐个定位真正的 agent( 调用,按顶层逗号拆参数:参数多于两个 deny,opts 必须是第二个(或唯一)参数且为对象字面量,只看其直接属性:model 必须是 haiku|sonnet|opus(可带 [1m])的普通字面量,或 agentType 指向已定义角色,否则 deny;同时给出 agentType 与 model 时,二者必须落在该角色的允许集内(脚本级 model 会覆盖定义,Explore 配 opus、implementer 配 haiku 都 deny);model 是变量、拼接表达式、重复出现、opts 里有 ... 展开都 deny;出现 Fable 模型或 Fable 角色 deny;agent/workflow 只能直接调用,别名、.call/.apply、?.()、globalThis.agent 与代码里的 \u 转义标识符一律 deny;调用 workflow() 嵌套子 Workflow deny,因为子脚本无法检查;字符串、模板、正则或块注释未闭合、括号不配对、无法读到脚本、以及整个脚本解析不出任何 agent 调用也 deny;内置 Workflow(如 /deep-research)没有可读脚本,插件 Workflow 的脚本 Hook 不读,两者一律 deny。effort 不做强制:它影响成本但不改变模型档位,脚本省略 effort 时继承主会话当时的档位,那个档位由用户按项目决定。2026-09-10 复核时发现旧版"按 agent( 切段"的启发式有两个反向缺陷:prompt 文本里出现 agent( 会让合规脚本被误拒(当天现场复现两次),而文件后文任何位置的 model: 'sonnet' 又会让缺模型的调用误过;改成词法解析后,Opus 对抗式审查分两轮又找出 16 类问题(正则字面量里的反引号或引号让扫描器失明、x++ / 被判成正则、别名调用、重复键、第三个参数、只传一个对象参数、spread、字面量拼接、深度 1 长字符串的二次方扫描让 20 KB 脚本卡 74 秒等)和两条崩溃即放行的路径(Test-Path 抛异常后 exit 1,非阻断),逐项修复后,第三轮只剩三条需要刻意构造的绕过(三元表达式取别名、globalThis['agent'] 计算属性、先把 globalThis.agent 存进变量),已用"禁止访问全局对象、计算属性字符串键与 eval/Function/import() 动态代码"关掉,108 个用例全部通过(2026-09-23 补上角色允许集与 Saved Workflow 解析范围的 8 个用例后为 116 个)。实测在 bypass 会话中,缺 model 的脚本在启动前被拦下,合规脚本则直接启动、不再弹窗。

同一天还暴露了一个与策略无关、但会让任何 PowerShell Hook 失效的问题:Claude Code 以 UTF-8 写入 Hook 的 stdin,而 Windows PowerShell 的 [Console]::In 按控制台代码页(本机为 GBK)解码,多字节字符后紧跟的引号会被吞掉,JSON 解析失败,Hook 以 exit 2 阻断一次完全合法的 SendMessage(触发字符是 Claude Code 自己加进 tool_input.content 预览里的省略号)。Hook 必须用 StreamReader([Console]::OpenStandardInput(), UTF8) 显式按 UTF-8 读取 stdin,并把 [Console]::OutputEncoding 设为 UTF-8。顺带确认了两条事实:Hook 输入里的 scratchpad_dir(2.1.257 起)、prompt_id(2.1.196 起)与 effort.level 都是 hooks 文档"通用输入字段"表里的字段,effort 只在 PreToolUse、PostToolUse、Stop、SubagentStop 这类工具上下文事件里出现,且要求当前模型支持 effort 参数(此前本文误写为未文档化);ask 附带的 additionalContext 在 bypass 会话里确实会随工具结果送达 Claude,这一条文档没有正面写。

这条检查必须存在的原因是 Claude Code 自带的 workflow-authoring Skill 要求写脚本时"默认省略 model,让 Agent 继承主会话模型"。这段文字在 2.1.282 的二进制里仍是运行时模板(与 2.1.267、2.1.270、2.1.280 文本只有运行时占位符不同):只有 CLAUDE_CODE_SUBAGENT_MODEL_FORCE 未设置时才渲染 model 选项和这句省略建议,设置了则完全不提 model。开启 ultracode 后,Claude 收到的正是这条系统级指令,用户 CLAUDE.md 里的"显式指定模型"无法稳定压过它。Prompt 层压不过它,但可以替换它:官方文档写明任一层级的同名 skill 会覆盖 bundled skill,所以在 ~/.claude/skills/workflow-authoring/SKILL.md 放一份个人版本,把 opts.model 改为必填、把 Ultracode 段的"token cost is not a constraint"改为遵守 dispatch-policy,显式加载 skill 时读到的就是这份。但覆盖有一个实测的边界:用 /effort ultracode 开启后,Claude Code 在下一轮直接注入的是内置文本而不是覆盖版(2026-09-10 在 2.1.267 上确认,注入内容含"Default to omitting it"和"token cost is not a constraint"),所以 ultracode 会话里真正起作用的只有 Hook。内置 workflow-authoring 文本存放在 claude.exe 里,没有解压副本;其他内置 skill(如 claude-api)在首次加载时才解压到 Temp/claude/bundled-skills/<version>/<hash>/,按版本重建,不要改它。覆盖 skill 负责让显式加载时的脚本一开始就正确,Hook 负责兜底。

Agent Team 的 Teammate 通过带 name 的 Agent 调用创建。它的模型解析顺序与普通 Subagent 相近但不完全相同:第一优先级是 spawn prompt 里用自然语言点名的模型,其后才是定义的 model、CLAUDE_CODE_SUBAGENT_MODEL、Lead 的模型;解析结果还要过组织的 availableModels 白名单,被拦的系列别名会换成该系列允许的最新版本。显式 model 的要求仍由 Hook 保证。官方文档写明 Teammate 始终继承 Lead 的 effort,无法逐个指定(split-pane 模式自 2.1.186 起才生效)。2.1.261 还修复了 in-process Teammate 第二轮重发首轮工具与 skill 声明、导致 prompt cache miss 的问题。这是保持 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS 关闭、需要时先把 Lead 降到 high 再开 Team 的直接理由。没有角色定义的内置类型(general-purpose、Plan)同样继承主会话 effort,Hook 对它们返回 ask,在非 bypass 会话里形成人工确认。

Saved Workflow 应在脚本中明确限制总节点、输入集合、parallel batch 和 repair 次数。Claude Code 的容量上限仍不是这里定义的 L0–L4 成本预算。

Stop Hook、/goal 与授权边界

/goal 创建会话级 Prompt Stop hook。参数定义终态,也充当首条工作指令。/goal go 没有验收证据;这次事件中,评估器把 W1–W7 和统一提交纳入终态,用户随后拒绝提交。

官方只说 "A goal doesn't change your permission mode";"Goal 不授予 stage、commit、push、publish 或破坏性操作的权限"是本机 CLAUDE.md 的规则,不是文档条款。将动作写进 Goal 前,先取得本轮授权。用户改变范围或撤回授权后,运行 /goal clear 或设置新条件。熔断交还控制权,但不会清除 Goal;会自动清除 Goal 的是四类失败:Claude Code 自行处理的认证失败、额度耗尽、自动压缩也解决不了的上下文溢出、模型不可用。其余失败自 2.1.269 起在交互会话里不再让 Goal 静默停住:服务过载、连接中断这类临时故障最多自动重试三次后暂停;API 限速、用量上限、Hook 结束回合这类重试也没用的失败直接暂停并说明原因,若会话正等待用量上限重置则到期自动续跑;CLAUDE_CODE_GOAL_CHECKIN_MINUTES=0 会同时关闭自动重试与 check-in。

这里有两个独立的熔断器,之前的版本把它们混在了一起。Stop hook 的通用上限来自 hooks-guide:"Claude Code overrides a Stop hook after it blocks eight times in a row without progress",可用 CLAUDE_CODE_STOP_HOOK_BLOCK_CAP(2.1.143 引入)调高;本机 2.1.259 在第 9 次阻断尝试时显示警告,与"8 次后接管"一致。/goal 自己的熔断器则是定性的:"If Claude keeps answering the evaluator without making progress (no tool use for several turns in a row), Claude Code stops the loop",没有固定次数。Stop hook 输入含 stop_hook_active,该值为 true 时返回成功可防止同一 Hook 再次阻断;hooks 文档写明 SubagentStop 同样收到 stop_hook_active,另加 agent_id、agent_type、agent_transcript_path 与 last_assistant_message;不过 2.1.271 起在 auto 模式下,Subagent 通过 SubagentHandback 调用交付报告(匹配 SubagentHandback 的 PreToolUse 或 PostToolUse Hook 从 tool_input.message 读到它),last_assistant_message 只剩收尾文字。

排查时用 /goal 查看条件和评估记录,用 /hooks 查看用户、项目与插件 Hook。本机 Codex Companion 1.0.6 的 Stop review gate 默认为关闭,因此没有触发本次事件。其 Hook 未检查 stop_hook_active;启用后,连续返回 BLOCK 会触发熔断。

本机还安装了第二个插件 Stop hook 来源:security-guidance(2026-09-10 已自动更新到 2.0.8,当前在 enabledPlugins 里为 false)注册了 asyncRewake 形式的 Stop hook,对 git diff 做 LLM 安全审查并以 rewake 消息返回;它会检查 stop_hook_active,不会参与熔断。同一插件的 SessionStart hook 以 bash 调用 Python 并设置 180 秒超时,是启用后每次启动的固定成本。列 Stop hook 清单时不能只数 /goal 与 Codex,也不能沿用上次审计的启用状态,每次都要重新读取 enabledPlugins 与插件版本。

Agent Team 默认关闭。只有成员必须持续互相通信和共同维护状态时才启用,并计入相同的任务总数和并发预算。

九、用户 Prompt 的真实位置

在 Anthropic 的指令层级中,system 和 managed policy 并不低于 user prompt。权限、工具白名单与 Hooks 也不会被一段用户文字绕过。

但 CLAUDE.md 本身是以用户指令方式加载的。在同一用户指令层内,当前对话更具体、更新的要求,通常比宽泛的长期偏好更能表达这次任务的意图。

因此,固定的“本次对话调度模板”很有价值:它可以收紧本次任务的等级、并发和委派 Fable 配额,但不能放宽上层策略或硬门禁。

完整配置资产集中放在Prompt 与 Agent 配置模板库,日常短 Prompt 集中放在个人 Prompt Tips,避免研究、配置与个人工作片段再次混在一起。

十、配置应该如何分层

内容推荐位置加载方式
跨项目个人硬偏好~/.claude/CLAUDE.md每次启动
跨项目分类规则~/.claude/rules/*.md全局或按路径
团队项目事实./CLAUDE.md项目启动
个人项目偏好./CLAUDE.local.md当前项目启动
路径专用规则.claude/rules/*.md匹配文件时
按需知识和操作.claude/skills/*/SKILL.md调用或命中时
调度预算与模型路由~/.claude/skills/dispatch-policy/SKILL.md首次委派前加载,coordinator 预加载
固定执行角色.claude/agents/*.md创建 Agent 时
稳定依赖图.claude/workflows/*.js执行 Workflow 时
强制门禁settings、permissions、Hooks匹配工具调用时
已验证经验事实Auto memory启动索引或按需读取

全局用户设置自 2026-09-25 起以 opus 别名为默认模型(Opus 5.5,原生 1M 上下文,不需要 [1m] 后缀),此前是 claude-fable-5-1[1m];Fable 5.1 按会话用 /model fable 切换,per-model 档位保存为 xhigh,没有 effort 字段的 Worker 继承会话当时的档位,无论它是多少。用户设置文件里的 top-level effortLevel: high 继续适用于没有 per-model override 的 Fable 5.1、Opus 5 及更早的模型,但不再适用于 Opus 5.5(默认 medium;model-config 与 settings-reference 写明这个旧式顶层键对 Opus 5.5 及之后的模型无效,条目按规范名匹配),所以文件改为带 modelSettings.claude-opus-5-5: high,取代原来的 claude-opus-5。coordinator profile 保持 high,因为经 --settings 传入的 effortLevel 对所有模型都生效。注意 model-config 的别名表只列 sonnet[1m] 与 opus[1m];fable[1m] 的文档出处是同一页的 2.1.257 迁移说明(直连 API 时,设置里保存的 claude-fable-5[1m] 会被改写成 fable[1m] 别名),再加上 2.1.260 changelog 提到的 ANTHROPIC_DEFAULT_FABLE_MODEL 上的 [1m] 标签。另外自 2.1.257 起,走 Claude apps gateway 的会话里 fable 与 best 别名仍解析到 Fable 5 而非 5.1,直连 API 的本机不受影响。2.1.267 新增 maxEffortLevel(顶层或 modelSettings 逐模型),在任何 provider 上都能给 effort 设硬上限、用户只能往低选;本机各角色的 effort 已写在定义里且 ultracode 默认关闭,暂未设置;settings-reference 明确它也会压住 skill 与 Subagent 的 effort frontmatter,所以一旦设低就会封住关键角色升 xhigh 和 implementer 返工升档,这正是本机保持不设的原因。同版本还修复了 effort frontmatter 在默认 effort 被 pin 的模型(Opus 4.7、Opus 4.8、Fable 5)上被忽略的问题;本机 fable 解析到 Fable 5.1、opus 到 Opus 5.5,不在其列。

专用 coordinator Agent/profile 另行固定为 Opus/high。委派角色继续显式路由为 Explore Haiku(超过 200K 上下文时 Sonnet/low)、planner/QA/reviewer Sonnet/high、implementer Opus/high、critical roles Fable/high。Codex 委派(包括 codex-rescue)计入同一账本,只在用户点名 Codex 时使用;插件自带的“主动使用”指引不覆盖这条规则。

每次派发显式指定角色模型,避免主会话默认值(Opus 5.5,或切换后的 Fable)泄漏到 Worker。

permissions.disableBypassPermissionsMode 与 defaultMode 是两项独立策略:只有必须禁止 bypass 时,才在 permissions 内设为 "disable";需要保留 CLI bypass 时应省略该键。defaultMode: auto 仍是默认值,启动时传 --permission-mode bypassPermissions 只为当前会话选择 bypass。

skillOverrides 不影响 plugin skills。要去掉重复的 Matt Pocock plugin skill 集合,应禁用对应插件,而不是编造 namespaced override。本机随后删除了 44 个已被 override 关闭的本地 skill 目录并清空 skillOverrides(2.1.261 新增的 /skill-doctor 可以直接列出每个 skill 的上下文成本与使用频次,下次清理应先跑它;但本机 DISABLE_TELEMETRY=1 同时关闭了 feature-flag 拉取,env-vars 文档写明这会让 /skill-doctor、Remote Control、claude import 与 advisor 不可用,要跑它得临时去掉这个变量),同时卸载了安装后从未启用的 impeccable、feature-dev、playwright 插件,并关闭了每次启动运行 Python 检查、每次 Stop 运行 LLM 审查的 security-guidance 插件。

CLAUDE.md 每个会话和每个自定义 Worker 都会加载,所以只保留跨项目工程契约;调度预算、任务等级和模型路由放在 dispatch-policy Skill,主会话首次委派前加载,coordinator 通过 skills: 预加载。

CLAUDE.md 的 @path 导入只改善维护,不节省 Token,因为导入内容仍在启动时展开。长任务模板应做成 Skill,按文件生效的规范应做成带 paths 的 Rule。

用户级规则只保存真正跨项目不变的约束。框架版本、构建命令、业务架构、测试矩阵和发布流程应留在项目范围,避免一个仓库污染另一个仓库。

十一、观测与停止

主 Agent 在第一次派生前应给出一次紧凑账本:任务等级、每次启动的权重与加权总数、计划并发、每个角色的模型与委派 Fable 配额。只有等级或剩余额度变化时再更新。

普通 Agent 的实际模型从 Agent 工具的返回结果核对,/tasks 面板列出后台任务;/workflows 能查看每个 Workflow Agent 的 Token 和耗时,并停止异常运行。官方建议 CLAUDE.md 控制在 200 行以内,超过 4 MiB 的文件会被整个跳过。

评估时要分开看非缓存输入、输出、缓存创建和缓存读取。缓存读取 Token 很大,不代表它与新输出 Token 具有相同价格。

达到任一预算上限后,正在执行的 Agent 可以完成当前步骤,但主 Agent不能 restart、resume、repair 或创建下一个 Workflow。

十二、本机落地记录

2026-09-04 对本机 Claude Code 2.1.260 做了一轮 deep review 并落地修正,2026-09-07 在 2.1.263 上复核,2026-09-10 在 2.1.267 上再次复核并修正。记录在此,便于日后对照版本变化重新验证。所有安装到 ~/.claude 的源文件已提交到 Dongshan-git/skills 的 ds/ 目录,按 Claude Code 版本记录的变更日志见 ds/CHANGELOG.md;之后每次 Claude Code 更新都会先复核再同步这三篇文章。

全局指令层

  • ~/.claude/CLAUDE.md 从 7.2KB 收缩到 2.6KB,只保留 Communication、Scope and evidence、Delegation、Delivery and Git 四节;绝对禁令只留给 commit、push、publish、破坏性操作与 Worker 范围。
  • 调度预算、任务等级和模型路由迁入 ~/.claude/skills/dispatch-policy/SKILL.md,主会话首次委派前加载,coordinator 通过 skills: 预加载。模型只写别名,不固定版本与价格。
  • 新增 ~/.claude/skills/workflow-authoring/SKILL.md 覆盖同名 bundled skill(派生自 Claude Code 2.1.260 的 bundled 文本,文件首行标注版本):opts.model 改为必填,Ultracode 段落改为遵守 dispatch-policy,示例代码全部带显式模型。已验证个人版本在会话内即时生效。

Agent 定义

  • critical-implementer 与 critical-reviewer 的 effort 从 xhigh 降为 high。
  • coordinator 去掉重复的路由段落,改为引用 dispatch-policy。
  • coordinator profile 增加 permissions.defaultMode: default,让 Worker 的 permissionMode: plan 在该 profile 下真正生效。

Hook(enforce-agent-dispatch.ps1)

  • 空输入、畸形 JSON、缺 tool_name 一律 exit 2。
  • Agent:缺 subagent_type 或 model 拒绝;已定义角色的模型不匹配拒绝;Explore 允许 haiku 或 sonnet;非关键角色使用 fable 拒绝;fork 拒绝;无定义的内置类型返回 ask;codex:* 放行。
  • SendMessage:目标含 critical- 或 fable 拒绝,发往 main 放行,其余 ask。
  • Workflow:读取脚本,任一 agent() 既无 model: haiku|sonnet|opus 也无已定义 agentType 即拒绝,出现 fable 拒绝,读不到脚本拒绝,合规才 ask。
  • 匹配器扩展为 Agent|Workflow|SendMessage。

settings 与插件

  • 关闭 security-guidance 插件;卸载从未启用的 impeccable、feature-dev、playwright。
  • 删除 44 个已被 override 关闭的本地 skill 目录并清空 skillOverrides。
  • 移除 Bash(npx:*) 与 PowerShell(npx:*) 许可;settings.json.bak 移入 backups/;.claude.json 的 autoUpdates 与 autoUpdatesChannel 对齐。
  • 项目 .claude/settings.local.json 删除已不存在的 mcp__context7__get-library-docs,补齐 PowerShell 对应许可。

实测结论

  • bypass 会话中,缺 model 的 Workflow 脚本在启动前被 Hook 拒绝;合规脚本直接启动且不弹窗,说明 bypass 下 Hook 的 ask 会被自动放行,只有 deny 有效。
  • 官方 workflow-authoring skill 要求脚本默认省略 model,ultracode 下 Claude 照此执行;用户级 Prompt 压不过它,同名个人 skill 可以覆盖它,Hook 负责兜底。
  • Agent Team 的 Teammate 模型由 Agent 调用的显式 model 保证,但 effort 始终继承 Lead,无法逐个指定。

第二轮:对照官方最佳实践后的调整

检索了 Claude Code 的 costs 与 model-config 文档、官方博客《Choosing a Claude model and effort level in Claude Code》、Fable 5.1 prompting 指南,以及 X 上 Anthropic 官方账号、Boris Cherny、Paweł Huryn 等人的实践。结论是原策略在"不继承主模型、不滥用 Fable"上正确,但把成本偏好写成了硬门禁。

  • Hook 的角色锁改为允许集合:reviewer、planner、qa 允许 sonnet 与 opus,implementer 允许 opus 与 sonnet,Explore 允许 haiku 与 sonnet。deny 留给缺模型、已定义角色越出允许集合、越界 Fable 和 fork;无定义的内置类型带合法别名时返回 ask。
  • 新增 reviewer-fable 角色(Fable/low,只读)。依据是官方 Fable 5.1 指南:"At low, Claude Fable 5.1 is often competitive with Claude Opus and Claude Sonnet models on cost per task while scoring higher." 它是普通启动,不占关键席位。
  • 关键席位从 L2 起可用,不再要求先把任务升到 L3。
  • dispatch-policy 写入官方的升档顺序:先问"没尽力还是不够懂",前者升 effort,后者换模型。
  • reviewer 与 critical-reviewer 的 prompt 加入对抗式框架("try to refute the change, prove it does not work"),来自 Claude Code 团队的公开建议。
  • CLAUDE.md 加入官方建议的措辞:认识一个名字不等于知道它的现状,快速变化的名字先检索再回答。

第三轮:2.1.263 复核

本机在 2026-09-06 自动升级到 2.1.263。用五个 Sonnet 读取器把三篇文章的 100 条事实断言与当前官方文档逐条比对:61 条确认、1 条与文档矛盾、10 条表述不精确,其余在补充页面后也得到确认。本次修正:

  • 内置 general-purpose 不预加载 skill,只有自定义定义的 skills: 字段才会;原文把它与自定义 Subagent 并列是错的。
  • "过度 prescriptive 的 prompt 会降低 Fable 5.1 输出质量"的出处是 Claude Code 自带 claude-api skill 的 model-migration.md 与 prompt-audit.md,不是公开的 prompting 指南。
  • Stop hook 的"8 次"上限与 /goal 的定性熔断器是两个机制,已拆开说明,并补上 CLAUDE_CODE_STOP_HOOK_BLOCK_CAP 与四类会自动清除 Goal 的失败。
  • Teammate 的模型解析顺序、availableModels 替换、split-pane 的 2.1.186 门槛,以及 2.1.261 的 Teammate cache 修复。
  • 补上 PreToolUse deny 在所有权限模式下生效的官方原文,把 bypass 下 ask 被放行明确标为本机实测。
  • fable[1m] 非文档化别名、gateway 会话中 fable 别名仍指向 Fable 5 的说明(第五轮更正:fable[1m] 的出处是 model-config 的 2.1.257 迁移说明)。
  • 新增事实:Large workflow 警告阈值、subagentPromptCacheTtl、Agent Team 在 plan mode 下约 7 倍 token、CLAUDE.md 200 行建议、/skill-doctor、bashOutputMaxChars。
  • Hook 的 Workflow 脚本切段改为大小写敏感并跳过 agent() 这类空参数提及,修复 prompt 文本里的 Agent(type) 被误判为缺模型调用的问题。
  • 本机 settings.json 增加 subagentPromptCacheTtl: "1h",dispatch-policy 补充 Fable medium 档与"API 有 refusal fallback 但 Claude Code 未暴露"两条说明(后一条在第四轮被证明是错的)。

第四轮:2.1.267 复核

本机在 2026-09-08 升级到 2.1.265、随后到 2.1.267。这次把官方文档按 .md 全量下载到本地逐字比对,用三个 Sonnet 读取器核对三篇文章、一个 Opus 审查配置并跑 25 个 Hook 用例、一个 Sonnet 分析 changelog、一个 Opus 做对抗式复核;三篇文章 126 条断言中 fable 文章 2 条矛盾、模板库 1 条矛盾 1 条过期 5 处快照漂移,prompt-tips 全部确认。本次修正:

  • Hook 的 Workflow 检查改为词法解析:旧的"按 agent( 切段"会误拒 prompt 文本含 agent( 的合规脚本(复核当天现场被拒两次),也会因后文的 model: 'sonnet' 误放缺模型的调用。新版标记注释、字符串、模板与正则字面量后按调用解析参数与 opts 对象;Opus 对抗式审查在第一版词法解析上分两轮又找出 16 类误放或误拒(正则里的反引号/引号、x++ / 误判为正则、别名与 .call/.apply/?.() 调用、\u 转义标识符、重复键、第三个参数、只传一个对象参数、spread、字面量拼接、别名正则的 $ 匹配尾部换行、深度 1 长字符串的二次方扫描、属性名叫 agent 被误拒)和两条 Test-Path 抛异常导致 exit 1 放行的路径,以及 sonnet[1m] 在 Agent 分支被拒的回归,全部修复;整个脚本解析不出 agent 调用、或调用少于两个参数也改为 deny。按 name 查找脚本改为从 Hook 输入的 cwd 逐级向上到 ~/.claude/workflows(去掉了插件缓存搜索,插件 Workflow 带命名空间冒号,本来就过不了名称校验);ask 的说明移入 additionalContext,因为 reason 不会给 Claude;SendMessage 对纯 agent ID 读取会话的 agent-<id>.meta.json 判断模型,Fable 或无法解析都 deny,session_id 只接受字母数字与连字符。最后把 stdin 改为显式 UTF-8 读取,修掉 GBK 控制台代码页吞引号导致合法调用被 exit 2 阻断的问题。三轮对抗后 108 个用例通过,测试脚本随 ds/hooks/tests/ 入库。
  • dispatch-policy 两句前提改正:opus/high 就是模型默认档而不是"低于默认的 xhigh";Claude Code 有分类器触发的自动回退(Fable 5.1 biology 到 Opus 5、cybersecurity 到 Opus 4.8),本机是 switchModelsOnFlag: false 才变为手动,回退是否作用于 Subagent 文档未写,手动重跑规则保留。
  • workflow-authoring 覆盖版按 2.1.267 二进制里的内置文本重新对齐:补回"Subagents get the same CLAUDE.md files injected at start"一段,首行改为 2.1.267 并记录两个事实:内置文本的"默认省略 model"只在 CLAUDE_CODE_SUBAGENT_MODEL_FORCE 未设置时渲染;/effort ultracode 注入的是内置文本而非覆盖版。
  • settings.json:弃用的 includeCoAuthoredBy 换成 attribution;删除已无插件的 impeccable marketplace 条目。评估过用 permissions.ask 把 git add、git commit、git push(含 git * commit:* 中间通配,覆盖 git -C <path> commit)变成任何模式都弹窗的硬门禁,因为 Bash(git:*) 在 auto 模式决策顺序第 1 步直接放行、分类器根本看不到;最终选择不启用,bypass 会话保持免打扰,git 授权继续由 CLAUDE.md 约束。
  • coordinator.md 的 Agent(...) 白名单加入 codex:codex-rescue,与 Hook 放行 codex:*、dispatch-policy 的 Codex 规则对齐。
  • critical-reviewer.md 去掉重复的对抗式句子。
  • 文章事实:默认 effort 是 high、SubagentStop 携带 stop_hook_active、Fable 5.1 引文按原句、command + args 自 2.1.139 起可用、security-guidance 当前为 2.0.8 且已禁用、DISABLE_TELEMETRY 会禁用 /skill-doctor;新增 maxEffortLevel、2.1.267 的 Subagent bypassPermissions 例外、PreToolUse 的 defer 与优先级、SendMessage to 可为 ID。
  • 明确保留的软约束:defaultMode: auto 下五个只读角色的 permissionMode: plan 无效,只靠工具列表与 Prompt;要硬保证只读只能让 review 会话走 coordinator profile 或去掉 reviewer 等角色的 PowerShell,这里选择不硬限制。
  • 15 处版本号引用与 changelog 逐条对照全部成立;2.1.265–2.1.267 没有条目推翻本文论断,相关的是 prompt-cache 修复(subagent resume、SubagentStart 上下文与预加载 skill 的前缀位置、/model 切换重发工具定义),它们让 subagentPromptCacheTtl: "1h" 的写入溢价此后才真正回本。

第五轮:2.1.270 复核

本机在 2026-09-13 前后经 2.1.268、2.1.269 升级到 2.1.270。2026-09-14 再次全量下载官方文档比对,用一个 Opus 和两个 Sonnet 读取器核对三篇文章、一个 Opus 审查配置、一个 Opus 做对抗式复核;41 条发现中 34 条确认、7 条降级、1 条驳回。本次修正:

  • claude --profile 不是 Claude Code 的参数(实测报 unknown option;--version 会短路,之前用它测不出)。coordinator profile 的正确用法是 claude --settings ~/.claude/profiles/coordinator.json:settings 文档写明 --settings 位于用户设置之上,所以 profile 里的 permissions.defaultMode: default 会压过全局 auto,Worker 的 permissionMode: plan 在该会话真正生效;文件里的 agent 也是文档化的 settings 键。ds/README.md 已改。
  • workflow-authoring 覆盖版:从 2.1.270 的 claude.exe 提取的内置文本与 2.1.267 只有运行时占位符不同,无需重排,只更新版本行,并让首段如实列出覆盖版偏离内置文本的全部策略句(此前只写了 model 规则与 Ultracode 段,漏了并发、规模与 resume 段里的 dispatch-policy 预算句);2.1.269 新增的 CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS 不写进覆盖版(内置文本没有它,本机也不设,dispatch-policy 的并发上限更低)。
  • 评估 CLAUDE_CODE_SUBAGENT_MODEL=opus,决定不设。它是解析顺序第 3 位的默认值,Hook 强制的逐次 model 与九个定义的 model 都排在它前面,也不影响内置 Explore/Plan;本机唯一会变的是以 forked subagent 运行的内置 skill(文档明确的是 /code-review;这类 skill 不经 Agent 工具,Agent|Workflow|SendMessage 匹配器看不到),会从主会话的 Fable 5.1/low 改到 Opus 5/high。按官方"Fable 5.1 在 low 档常与 Opus、Sonnet 单任务成本相当"的说法这点收益不明确,却要改动 Hook 两条 deny 文案、覆盖 skill 两句和两篇文章里"缺 model 就继承主会话模型"的表述。担心 Claude 自动启动 /code-review 时,文档给的开关是 skillOverrides: { "code-review": "user-invocable-only" }。CLAUDE_CODE_SUBAGENT_MODEL_FORCE 继续保持不设。
  • 文章事实修正:scratchpad_dir、prompt_id、effort.level 是文档化的 Hook 输入字段;maxEffortLevel 明确压住 skill 与 Subagent 的 effort frontmatter;fable[1m] 的文档出处是 model-config 的 2.1.257 迁移说明;Opus 5 自带分类器且 biology 命中无回退;defer 只在 -p 模式生效;ultracode 会话豁免 CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS,/subtask fork 与 resume 也不受它约束;Hook 从 2026-09-10 起就不再从插件缓存解析 Saved Workflow,两篇文章的描述改回与代码一致;/goal 自 2.1.269 起自动重试与暂停;Agent Team 的共享任务列表依赖 Task 工具,2.1.268 起 Fable 5.1、Opus 5、Sonnet 5 默认没有,需要 CLAUDE_CODE_ENABLE_TODO_TOOLS=1;Agent 工具入参在开启 Agent Team 后还有 name。
  • 记录但未改:Explore.md 的 effort: low 在 haiku 上无效(model-config 的 effort 表不含 Haiku 4.5),只在派成 sonnet 时生效;auto 模式下 Subagent 沿用主会话的 allow 规则,PowerShell(git:*) 使带 PowerShell 的只读角色执行 git 提交时不会弹窗,仍只由 CLAUDE.md 约束;Hook 对 codex:* 带合法别名直接放行,"只在用户点名时用 Codex"只是 Prompt 规则;permissions.deny: ["Agent(model:fable)"] 这种文档化的参数规则会连 reviewer-fable 与 critical 角色一起拦(Hook 要求它们显式传 model: fable),不能作为第二层;skipWorkflowUsageWarning 未文档化但二进制存在,Large workflow 警告按文档只受 workflowSizeGuideline 与 ultracode 影响。
  • 2.1.268–2.1.270 没有条目推翻本文论断。直接相关的:attribution 提醒不再压过 CLAUDE.md 规则;Windows 上后台 PowerShell 命令不再随会话退出而停止;2.1.270 修复 2.1.269 引入的只读 git 命令误弹窗;auto 模式的拒绝消息会点名规则;Task 工具在新模型上默认关闭;CLAUDE_CODE_BG_TASKS_REPORT_RUNNING 与 bashEditDiffEnabled 同样尚未进入文档,本机都不需要。

第六轮:2026-09-14,把速度杠杆从成本杠杆里拆出来

同一天复盘发现,前五轮把并发上限当成了成本工具。在 Max 20x 订阅上,消耗量由"启动次数 × 每个 Worker 装入的上下文 × 模型档 × effort"决定,4 个 Worker 排队跑和同时跑花费完全一样;Workflow 里并行反而更省,因为兄弟 agent 共享 prompt cache 前缀。第五轮那次 5 agent 复核就因策略并发 3 多等了约十分钟,token 一分没省。本次调整:

  • settings.json 与 profiles/coordinator.json:删除 CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY=4(它把每个会话里普通的并行 Read、Grep、Glob 压到 4 路,不省 token),CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS 从 4 提到 12(防失控 fan-out 的护栏,成本由启动预算管住,出现 429 再降到 8),workflowSizeGuideline 从 small 改 medium(它只是给模型的建议,真正的上限是加权预算)。
  • dispatch-policy:预算从"启动次数"改为 Opus 当量,haiku 0.2、sonnet 0.4、opus 1、fable 2,reviewer-fable(low)按 1、critical 角色按 2;删掉并发列和"单 Workflow 启动数"列,改为"一个阶段里所有独立启动全部并行,只有依赖前一步结果的阶段才串行";"默认串行"删除。各等级的当量数值沿用原来的启动数,所以 Opus 为主的任务预算不变,Sonnet、Haiku fan-out 可以宽得多。
  • coordinator.md 同步去掉"默认串行"。Hook 不变,它不检查并发。
  • 保留的成本杠杆:CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=1、subagentPromptCacheTtl: "1h"、ultracode: false、角色路由与 Fable 闸门。/fast 不默认开:它用 Opus 快速输出,在订阅账户上走 usage credits,是额外花钱换时间。

第七轮:2.1.280 复核(2026-09-23)

本机在 2026-09-18 自动升级到 2.1.280。2026-09-23 再次全量下载官方文档,并对照 2.1.271–2.1.280 的 changelog(568 条)比对,这次用一个 Workflow 跑:六个读取器(一个 Sonnet 读 changelog、一个 Opus 审 env-vars 与 settings、一个 Opus 加两个 Sonnet 核对三篇文章、一个 Opus 审查配置并跑 Hook 用例),再由一个 Opus、一个 Sonnet 做对抗式复核;53 条发现中 37 条确认、14 条降级、2 条驳回,复核者另补 3 条。真正改变本机事实的是 2.1.280 发布的 Opus 5.5。本次修正:

  • 模型与 effort:2.1.280 起 opus 别名指向 Opus 5.5(每百万 token 输入 4 美元、输出 20 美元,缓存读取 0.20 美元),默认 effort 是 medium。用户设置文件里的顶层 effortLevel 对 Opus 5.5 及之后的模型不再生效(经 --settings 传入时仍对所有模型生效,所以 coordinator profile 本来就是 high),modelSettings 条目又按规范名匹配,此前 /model opus 的会话实际跑在 medium;settings.json 因此把 modelSettings.claude-opus-5 换成 claude-opus-5-5: high。Fable 5.1 的 per-model 档位改为描述成用户按项目的选择,文章不再写死某一档;没有 effort 字段的 Worker 继承会话当时的档位。
  • dispatch-policy:权重按与 Opus 5.5 的标价比值重算为 haiku 0.25、sonnet 0.5、opus 1、fable 2.5,critical 角色 2.5,reviewer-fable 仍按 1;示例改为 L2 用掉 3.25、L3 用掉 4、八个 Sonnet finder 用掉 4。路由说明改为 opus/high 比 Opus 5.5 的 medium 默认高一档、定义里的 effort 优先于会话档位;refusal 条目补上 Opus 5.5 同样带分类器、回退相同(biology 到 Opus 5,cybersecurity 到 Opus 4.8)。
  • workflowSizeGuideline: medium 在 2.1.271 从少于 15 降为少于 10;显式选定后 Large workflow 警告阈值换成该档的 Agent 数,本机一次运行超过 10 个 Agent 就会提示。
  • 三项此前只见于 changelog 的设置已进入文档:CLAUDE_CODE_WORKFLOW_MAX_CONCURRENT_AGENTS(1–256,默认最多 16,值越高内存占用越大)、CLAUDE_CODE_BG_TASKS_REPORT_RUNNING、bashEditDiffEnabled,本机都不设。
  • 评估 omitClaudeMd(2.1.271),决定不用:CLAUDE.md 承载 Worker 契约,任何角色都不应跳过它。
  • 记录但未改:2.1.271 起 auto 模式下 Subagent 经分类器审查的 SubagentHandback 调用交付报告,SubagentStop 的 last_assistant_message 只剩收尾文字,Agent 结果的 content 也只是一句提示(resolvedModel 不受影响;coordinator profile 跑在 default 模式,不受影响);2.1.271 起 Workflow 碰到用量上限会暂停,而不是让其中的 Agent 失败;Task 工具在 Opus 5.5 上同样默认关闭,与 Fable 5.1、Opus 5、Sonnet 5 一样,Agent Team 的共享任务列表仍需 CLAUDE_CODE_ENABLE_TODO_TOOLS=1。
  • Hook:Workflow 脚本里的 agentType/model 组合改为按与 Agent 调用相同的角色允许集合检查(此前脚本里 Explore 配 opus、implementer 配 haiku 只得到 ask,同样的组合走 Agent 工具却被拒);Saved Workflow 只在工作目录到仓库根(第一个含 .git 的上级目录)之间查找,再到 CLAUDE_CONFIG_DIR 或 ~/.claude,不再一路走到盘符根;新增 8 个用例,116 个全部通过。
  • workflow-authoring 覆盖版:版本行改为 2.1.280(2.1.276、2.1.277、2.1.280 的内置文本与 2.1.270 只有运行时占位符不同);并发、Ultracode 与规模段落不再提按等级的并发上限;首段注明内置 Ultracode 段里"倾向用 Workflow 编排并做对抗式验证"一句按策略省略。
  • skipWorkflowUsageWarning 的真实含义:2.1.280 二进制把它标为 @internal,记录的是 auto 模式下 Workflow 用量提示的同意,与只提示的 Large workflow 警告无关。
  • 未启用的选项:syncClaudeAiSkills 与 syncClaudeAiPlugins(2.1.273/2.1.275)在本机无效,因为 DISABLE_TELEMETRY=1 关闭了 feature-flag 拉取,这同时关掉 advisor 工具、artifact 评论与 /skill-doctor(AGENTS.md 回退自 2.1.281 起不再依赖 feature flag,telemetry 关闭的会话也生效),也是 Windows 上必须保留 CLAUDE_CODE_USE_POWERSHELL_TOOL=1 的原因;workflowKeywordTriggerEnabled 保持默认 true(即使 ultracode: false,Prompt 里的 ultracode 一词仍会启动 Workflow,Hook 会检查那次调用);CLAUDE_CODE_GATEWAY_HINT_HEADERS=0(2.1.273)是 CLAUDE_CODE_ATTRIBUTION_HEADER=0 的隐私对应项,直连时不省什么,暂不设。
  • 驳回的一条:有发现认为"Fable refusal 改用 opus/xhigh 重做"在 Opus 5.5 上更糟。Opus 5 在 2.1.280 之前就带分类器、biology 直接 refusal,重做路径并没有变差,规则保留。
  • 2.1.271–2.1.280 直接相关的条目:Opus 5.5 成为默认 Opus,per-model /effort 出现之前保存的档位不再作用于新发布的模型(2.1.280);auto 模式的 SubagentHandback、omitClaudeMd、medium 规模建议从 15 降到 10、Workflow 碰到用量上限暂停而不是让 Agent 失败、Windows 上临时输出路径达到 260 字符时 PowerShell 命令失败的修复(2.1.271);gateway hint 头与 CLAUDE_CODE_GATEWAY_HINT_HEADERS(2.1.273);claude.ai skill 与插件同步及其关闭键(2.1.275);Subagent 结果带来源标头交付、resume 的 Subagent 保留 MCP 工具定义以命中 prompt cache、移除 TaskOutput 工具(2.1.277);resume 的 fork Subagent 保留工具列表以命中 prompt cache,启动方压缩上下文时不再丢失已完成 Subagent 的报告(2.1.280)。

未改动

  • 主会话保持 claude-fable-5-1[1m],Fable 的 per-model 档位由用户按项目调整;defaultMode 保持 auto;DISABLE_TELEMETRY 保持开启。
  • Context7 API key 保持原样。

2026-09-24 至 09-25 只改了 Hook,没有重新核对官方文档:

  • 加入每会话 Fable 上限:从会话目录的 agent-*.meta.json 统计已启动的 Fable Worker,达到 CLAUDE_FABLE_MAX_PER_SESSION(默认 7)即拒绝,读不到会话目录也拒绝。
  • 合规 Workflow 的决定从 ask 改为 allow。此前 ask 只在非 bypass 会话(本机默认 auto)里弹窗;现在是否启动 Workflow 只由模型侧的 opt-in 规则决定,所有 deny 不变,SendMessage 与未定义角色的 Agent 仍是 ask。116 个 Hook 用例中 38 个 Workflow 用例的期望随之改为 allow,全部通过。

第八轮:2.1.282 复核(2026-09-25)

本机在 2026-09-24 自动升级到 2.1.282。这一轮只对照 2.1.281 与 2.1.282 的 changelog,以及当天为操作规范一文重读的 prompt-caching、sessions、costs、goal、permission-modes、model-config 文档,没有全量重新下载文档。从 claude.exe 提取的 bundled workflow-authoring 文本按句比对,与覆盖版的差异只有覆盖版文件头列出的策略段与运行时占位符,所以 2.1.282 的内置文本与 2.1.280 一样只差占位符,覆盖版只改版本行;Hook 116 个用例全部通过。

  • 用户决定:全局主会话默认从 claude-fable-5-1[1m] 改为 opus 别名(Opus 5.5,原生 1M 上下文,modelSettings 固定 high);Fable 5.1 按会话用 /model fable 切换,per-model 档位 xhigh 是有意的;Worker 数量不设硬上限,Hook 继续只查模型。
  • 新增两个机制:全局 CLAUDE.md 的 Compact instructions 段,让手动与自动压缩保留任务与验收标准、验证命令及结果、改动文件、待授权动作、派发账本与 handoff 路径;个人 handoff skill,按固定结构把交接写到 ~/.claude/projects/<project>/handoff/HANDOFF.md。按生命周期整理的操作规则单独成文:《Claude Code 项目协作操作规范》。
  • 文章事实修正:AGENTS.md 支持自 2.1.281 起在 telemetry 关闭的会话里也生效,不再随 feature-flag 拉取一起关掉;auto 模式的分类器审查自 2.1.282 起在 telemetry 关闭的会话里默认走服务端,CLAUDE_CODE_AUTO_MODE_SERVER=0 退回本地分类器请求;attribution 新增 false 简写,旧版本会整个跳过含它的设置文件,本机保持对象写法。
  • 与本文相关的 changelog 条目:恢复会话时重发历史的多处修复(避免打断 prompt cache、丢失早先的推理)与大会话恢复提速(2.1.281、2.1.282);auto 模式在新进程里恢复会话后分类器可复用先前的 prompt cache(2.1.281);compaction 请求被拒绝时改用回退模型重试(2.1.282);--agents 接受 JSON 文件路径、/workflows 里 x 可停止运行、提示栏的后台 Workflow 行显示 Agent 数与 token 数(2.1.281);ultracode 的视觉提示改为普通样式(2.1.282)。
  • 未改:DISABLE_TELEMETRY 与 defaultMode: auto 保持;promptCacheTtl 不设,因为主会话在套餐额度内已是 1 小时 TTL,只有扣 usage credits 时才降到 5 分钟。

结语

成本优先不是统一降级,而是按会话目标选择主模型,让显式委派的廉价 Agent 承担搜索与常规工作,仅把委派的 Fable/high 配额用于一次真正关键的问题。

好的调度系统还必须限制加权启动总数与同时活动的 Workflow 数,让独立工作并行而不是排队,并防止 restart、resume、Workflow 拆分和 Ultracode 绕过预算。

参考资料