---
title: Claude Code 成本优先的 Subagent 与 Workflow 调度实践
description: 基于 Claude Code 2.1.322，梳理多代理能力边界、任务等级、并发预算和 Fable 使用配额
date: 2026-09-02
updated: 2026-11-10
author: DS-Dev
tags:
  - Claude Code
  - Subagent
  - Workflow
  - AI 工程
featured: true
---

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

本文以本机 Claude Code 2.1.322 为基线（初稿写于 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 的变更复核，2026-10-11 按 2.1.283–2.1.296 的变更和全部官方文档逐条复核；2026-10-15 只按 2.1.299–2.1.300 的变更检查了配置，2026-11-09 按 2.1.301–2.1.319 的变更、当天下载的相关文档与 2.1.317–2.1.319 二进制复核，2026-11-10 按 2.1.321–2.1.322 的变更、Anthropic 的选型指南与 Fable 5.2 文档复核），研究 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 配置模板库》](/blog/claude-code-agent-workflow-prompts/)。日常直接发送的 Workflow、Subagent、Agent Team 与工程实践片段，集中保存在[《我的 AI Agent Prompt Tips》](/blog/personal-ai-agent-prompt-tips/)。

## 一、先分清五种执行机制

| 机制       | 上下文与协作方式             | 适合场景                     | 成本风险                              |
| ---------- | ---------------------------- | ---------------------------- | ------------------------------------- |
| 主 Agent   | 使用当前会话上下文           | 小任务、强依赖当前讨论       | 长会话持续携带历史上下文              |
| Subagent   | 独立上下文，结果返回主 Agent | 有界搜索、实现、审查、验证   | 委派过细会重复加载项目背景            |
| Fork       | 继承完整父会话，再独立继续   | 必须理解完整讨论的分支       | 失去输入隔离，并行分支放大总量        |
| Workflow   | JavaScript 编排 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`，以及 2.1.292 起的 `effort`（非 fork），并按条件设置名称、后台运行或 worktree 隔离。

在 2.1.280 中，模型解析顺序是：本次调用的 `model`、Agent 定义的 `model`、`CLAUDE_CODE_SUBAGENT_MODEL`、主会话模型；2.1.319 的 sub-agents 文档顺序不变，另写明已安装 mod 的 `agent.spawn` 钩子若设置了模型，会取代本次调用的 `model`（本机没有装这类 mod）。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 定义、`--agents` JSON 或 SDK `AgentDefinition`。2.1.292 起 Agent 工具对非 fork Subagent 也接受逐次的 `effort`：它覆盖定义里的 `effort`，resume 后继续生效，只有 `CLAUDE_CODE_EFFORT_LEVEL` 优先于它；工具说明要求 Claude 只在用户或 CLAUDE.md、skill 这类指令明确要求某一档时才传。本机把它当作同一角色上的第一步升档（"没尽力"），不改变这次启动的权重；Fable 角色的权重以定义里的 effort 为前提，所以 Hook 读取 `tool_input.effort`（2026-10-11 实测 PreToolUse 输入里有这个字段），对 Fable 角色带 `effort` 一律 `deny`。要在 permissions 层限制它，permissions 文档的参数规则 `Tool(param:value)`（值可带 `*` 通配，只用于 deny 与 ask）可以写成 `Agent(effort:max)`、`Agent(effort:xhigh)` 这样的 deny；不要用 `ask`，它在 bypass 会话里会被直接放行。

普通 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 里；2026-10-11 在 2.1.296 上实测，这里的"会话 effort"是会话的 effort 设置按该 Agent 自己的模型解析出的档位，而不是主会话当时的档位：主会话 effort 为 xhigh 时，一个 `model: 'sonnet'`、不带 `effort` 的 Agent 跑在 medium（Sonnet 5.5 的默认），带 `effort: 'low'` 时跑在 low。2.1.317 的 changelog 把它写成规则（model-config 文档只写换了模型时会话档位不适用）：没有自己 `effort` 的 Subagent 或 Teammate 只在跑主会话模型时继承会话档位，换了模型就用该模型保存的档位或默认值，所以 Opus 主会话里不带 `effort` 的 `opus` Workflow Agent 跑在主会话的档位上。2.1.316 新增的 `CLAUDE_CODE_SUBAGENT_EFFORT`（env-vars 文档未收录）只在定义与调用都没写 effort 时生效，设置后 2.1.319 的 bundled skill 把"省略则继承会话 effort"那句换成"use the configured subagent default"；本机九个角色都写了 effort，保持不设。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 再次运行。resume 这条路径已收窄：2.1.305 起 resume 从运行 journal 直接返回已完成的 `pipeline()`、`parallel()` Agent，2.1.318 又修复了用量上限后 resume 重跑已完成 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。

## 三、能力边界表

| 控制项              | 普通 Agent       | Workflow `agent()`    | Agent SDK                         |
| ------------------- | ---------------- | --------------------- | --------------------------------- |
| 逐次选择模型        | 支持             | 支持                  | 支持                              |
| 逐次选择 effort     | 支持（2.1.292+） | 支持                  | 通过定义或 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 | 允许集合 | 典型任务 |
| --- | --- | --- | --- |
| 专用主协调 profile | Opus / high | 固定 | 拆解、调度、证据整合与验收 |
| `Explore` | Haiku / medium | haiku, sonnet | 文件定位、窄搜索、证据清单 |
| `planner` | Sonnet / high | sonnet, opus | 有界计划、依赖分析；跨模块架构升 Opus |
| `implementer` | Opus / high | opus, sonnet | 常规生产与测试实现；可精确描述的机械改动降 Sonnet |
| `qa` | Sonnet / high | sonnet, opus | 构建、测试、复现、浏览器验证 |
| `reviewer` | Sonnet / high | sonnet, opus | 常规独立审查；权限、数据、并发、迁移、公共契约升 Opus |
| `reviewer-fable` | Fable / low | fable | Sonnet 判断不够时的只读审查，每任务成本与 Sonnet/high 相当 |
| `critical-implementer` | Fable / high | fable | 关键复杂实现 |
| `critical-reviewer` | Fable / high | fable | 安全、并发、迁移与架构审查 |

默认值是起点不是上限。每次调用可以在允许集合内升降档，Hook 只拒绝集合之外的模型。升档顺序来自 Anthropic 的选型指南《Which Claude model should you build with》：先确认 Worker 能用测试、构建或脚本验证自己的工作；再在同一角色上升一级 effort（Agent 调用逐次传 `effort`，Fable 角色除外）；最后才换大一号模型，并从比小模型更低的 effort 起步。关键 Fable 角色是最后一步的例外，保持定义里的 high：它们只接点名的难题，Fable 5.2 提示指南也说能力增益大多在 high 就已具备。判断成本要按每个完成的任务算，需要多跑一轮的便宜 Worker 并不便宜。2026-11-10 之前这里按旧版指引分"没尽力"与"不够懂"两种情况，新指南把验证放在了升档之前。

规则里只写 `haiku`、`sonnet`、`opus`、`fable` 别名，由 Claude Code 解析到当前一代，不固定具体版本和价格。当前一代的标价差距并不均匀：Sonnet 5.5 到 Opus 5.5 是 2 倍，Opus 5.5 到 Fable 5.2 也是 2 倍，Haiku 5.5 到 Sonnet 5.5 却是 20 倍（Haiku 的 prompt 超过 100K token 后按更高单价计，差距缩到 4 倍）；这些价格只见于 changelog，model-config 只写了 Haiku 5.5 在 100K 以上更贵。档位之外，真正放大成本的是轮次与上下文长度。Explore 的搜索需要更多上下文或轮次时，可在允许集合内改用 Sonnet，effort 同样是 medium。

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

复杂工程会话可显式启动专用 Opus/high coordinator profile 负责拆解与验收，并把委派的 Fable/high 限于一次关键判断。该 profile 不改写全局主会话默认值。让 Fable 5.2 当 coordinator 是一个待做的实验，见第十二轮。

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

预算限制的是一次用户任务的加权启动总数和同时活动的 Workflow 数。启动按 Opus 当量计：每次启动按模型加权，haiku 0.125、sonnet 0.5、opus 1、fable 2。权重是 Anthropic API 标价与 Opus 5.5 的比值：Opus 5.5 是 2.1.280 起 `opus` 别名所指，每百万 token 输入 4 美元、输出 20 美元；Sonnet 5.5（2.1.284 起 `sonnet` 别名所指）输入 2 美元、输出 10 美元，得 0.5；Fable 5.2（2.1.321 起 `fable` 别名所指）输入 8 美元、输出 40 美元，得 2；Haiku 5.5（2.1.293 起 `haiku` 别名所指）按 prompt 超过 100K token 时的单价计（输入 0.50 美元、输出 2.50 美元），得 0.125，因为一次启动后面的轮次可能越过 100K，而账本看不到每一轮的 prompt 长度，按基础单价（输入 0.10 美元、输出 0.50 美元）则只有 0.025。订阅额度的消耗大致同比，这是假设，不是有出处的事实。两个角色例外：`reviewer-fable`（Fable/low）按 1 计，这是从 Fable 5.1 沿用的假设（当时官方说"Fable 5.1 在 low 档常与 Opus、Sonnet 单任务成本相当"），还没在 5.2 上实测，Fable 5.2 提示指南只说 low 适合"fast, intelligent subagents"，得分接近 Fable 5.1 在更高档位的成绩；两个 critical 角色（Fable/high）按 2 计。effort 改变一次启动的 token，但不改变权重，逐次传入的 `effort` 也一样。并发不再是预算项，见第六节。

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

举例：一个 Opus implementer、一个 Sonnet qa、一个 Sonnet reviewer 加五次 Haiku Explore 用掉 L2 的 2.625；三个 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 会话里等于放行。用户自 2.1.319 起从 `/tasks` 重新打开已完成 Subagent 的路径完全不经过 Hook，见第八节。

成本优先的会话不应把 `/effort ultracode` 设为默认。Ultracode 会为每个实质任务自动设计 Workflow，还会跳过 auto 模式下首次启动的 Workflow 批准与大型运行警告；2.1.284 起 `/effort ultracode` 与 `ultracode` 设置不再改变 effort，会话保持原档位，只有 `claude --effort ultracode`（以及 SDK 的 `effortLevel: "ultracode"`）同时把 effort 设为 xhigh；sub-agents 文档明确 ultracode 会话不执行 `CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`，也就是最后一道数字上限一起失效。

## 七、Fable 使用闸门

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

`reviewer-fable` 用 Fable/low 做只读审查。Fable 5.2 提示指南写明，low 适合快速而聪明的 Subagent，Anthropic 测试里 5.2 在 low 的得分接近 Fable 5.1 在更高档位的成绩；此前 Fable 5.1 指南也说 low 下的 Fable 在每任务成本上常与更高 effort 的 Sonnet 或 Opus 相当且得分更高。所以它是普通启动，从 L1 起可用，计入等级总数，不占关键席位；因为 low 下 Fable 较少主动检索，prompt 要求它先读再下结论。同一份 5.2 指南还说模型在 low 与 medium 更容易在任务完成前收尾，建议这时在系统提示里加一段 Finishing work；那段文字在官方回放里让输出 token 多了约 30%，所以本机先观察，`reviewer-fable` 出现没看完 diff 就结束的情况再加进定义。

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

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

关键角色从 high 起步，这与 Fable 5.2 提示指南一致：从 API 默认的 high 开始，"Most of the gain in capability is already present at `high`"，xhigh 在官方编码评测里只"raised scores slightly and used many more tokens"，并且换代后要重新试档，不沿用为 Fable 5.1 调好的设置；只有 eval 证明 high 仍有余量时才升到 xhigh。implementer 的 Opus/high 与 planner、qa、reviewer 的 Sonnet/high 都比模型默认高一档：`opus`、`sonnet`、`haiku` 分别指向 Opus 5.5（2.1.280 起）、Sonnet 5.5（2.1.284 起）与 Haiku 5.5（2.1.293 起），model-config 写明这三个模型默认都是 medium，Opus 4.7 默认 xhigh，其余支持 effort 的模型默认 high；2.1.284 起 ultracode 也不再把默认抬到 xhigh，只有 `--effort ultracode` 会。定义里的 `effort` 优先于会话档位，所以 `implementer.md` 固定的 high 在 Opus 5.5 上照样生效，Explore 的 medium 正好等于 Haiku 5.5 的默认；Agent 调用逐次传入的 `effort` 又优先于定义。返工或验证失败时再升档。

Fable 带安全分类器，可能以 `refusal` 结束响应。官方说明在源码中查找漏洞是允许的，误拒主要来自"能否编译"式的提问、冷门语言和工具输出里的 base64。Claude Code 本身有分类器触发的自动回退：model-config 写明 Fable 模型与 Opus 5.5 被 biology 分类器标记时重跑 Opus 5，被 cybersecurity 标记时重跑 Opus 4.8，并在 transcript 里提示；Opus 5 自己也带分类器，cybersecurity 命中同样重跑 Opus 4.8，biology 命中则直接以 refusal 结束、没有回退模型；Sonnet 5.5 被 cybersecurity 标记时重跑 Sonnet 5，被 biology 标记则以 refusal 结束、没有回退。2.1.312 起自动切换也覆盖 Claude Code 不认识的模型名（如自定义部署名），`CLAUDE_CODE_DISABLE_REFUSAL_FALLBACK=1` 可关闭这类切换；2.1.314 起 `ANTHROPIC_DEFAULT_OPUS_MODEL`、`availableModels` 或 `deniedModels` 只留下较旧的 Opus 或一个都不留时，被标记的请求也改为换模型重试，而不是以 refusal 结束。本机保持 `switchModelsOnFlag: false`（`/config` 里的 "Ask each time"），目的是不让任何模型被静默替换：交互主会话暂停让用户选择，`-p` 下以 refusal 结束该轮；Agent 工具派出的 Subagent 不弹提示，2.1.318 起被标记的请求让该 Subagent 以 `Agent terminated early due to an API error` 加 refusal 消息失败，由 Claude 收到错误后决定怎么处理（model-config 的 "Subagents switch or fail without asking"；此前不论选哪一项都在回退模型上重跑）。改选 "Switch automatically" 能让 Subagent 回到回退模型上重跑，但主会话也会随之不经询问切换。Workflow Agent 与 Teammate 是否同样失败，文档没有写。本机规则：委派的 Fable Worker 这样失败或以 refusal 结束时，先报告，不算"一次有证据的常规角色失败"，在对应的常规角色上以 Opus/high 重做一次（critical-implementer 对应 implementer，critical-reviewer 与 reviewer-fable 对应 reviewer；此前写的是 Opus/xhigh），不再消耗 Fable 配额。这次重做跑在同样带分类器的 Opus 5.5 上，可能再被标记而失败，那时停下来报告用户，不再换模型；biology 类在 Opus 5 上没有回退，换模型只会再得到一次 refusal，要改写任务。2.1.319 还会在安全机制停掉 Subagent 后提示 Claude 用更窄的 prompt 重试或告诉用户、而不是自己动手做，本机以上面的显式规则为准。Agent 结果里的 `resolvedModel` 记的是 Subagent 启动时的模型；`modelsUsed` 现在只来自 API 错误后的回退链切换，不再来自分类器标记。

全局主会话默认自 2026-09-25 起是 `opus` 别名所指的 Opus 5.5（`modelSettings` 自 2026-11-10 起为 medium，见第十二轮）；Fable（2.1.321 起是 Fable 5.2）只在需要的会话里用：在 `/model` 选择器的 Fable 行按 `s`（仅本会话），或用 `claude --model fable` 启动；直接输入 `/model fable` 会把 `model: fable` 写进用户设置，之后的新会话都从 Fable 开始。它的 per-model 档位 2026-11-10 起保存为 medium，难题在本会话里升到 high；此前为 Fable 5.1 保存的 xhigh 在别名改指 5.2 后已不匹配。定义里没有 `effort` 字段、Agent 调用也未传 `effort` 的 Worker（包括 general-purpose 这类内置类型），只在跑主会话模型时继承会话档位，换了模型就用该模型保存的档位或默认值（2.1.317 的 changelog；model-config 文档只写换了模型时会话档位不适用；2026-10-11 在 2.1.296 上对 Workflow Agent 实测过换模型的情形，内置类型没有单独测）。2.1.316 新增的 `CLAUDE_CODE_SUBAGENT_EFFORT` 只在定义与调用都没写 effort 时充当默认值，本机保持不设。档位越低，Fable 越可能直接凭记忆回答并减少检索，因此应继续用真实工作负载评估效果。

Fable 5.2 在长串工具调用里可能很少写给用户看的文字，第一次调用工具前也可能不说要做什么；它写在工具调用之间的进度更新以 progress-update `thinking` 块返回。Prompt 可以明确要求启动说明、简短阶段进度和独立的最终 recap，同时写清完成任务与范围边界；提示指南给出的那句官方文字在测试里让每任务输出 token 多约 20%，只在有人实时看着时用。

主 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，也拒绝 Fable 角色带逐次 `effort` 或 `name` 的调用。L3/L4 用户批准仍由 Prompt 与人工治理，不是该 Hook 的检查项。

2.1.296 的 Agent 工具入参仍没有 `resume`（本机 Agent Team 关闭的会话里，工具 schema 只有 `subagent_type`、`prompt`、`description`、`model` 与 `isolation`，2026-09-25 在 2.1.282 会话中再次确认；2.1.296 的二进制 schema 多了 `effort`，基础 schema 还有 `name` 与按条件出现的 `run_in_background`。`name` 让运行中的 Subagent 可以被 `SendMessage({to: name})` 寻址、完成后按名 resume；开启 Agent Team 时带 `name` 的调用会变成 Teammate，除非它是 fork 或在调用里传了 `isolation`。本机 Hook 对 Fable 角色带 `name` 一律 `deny`，因为 Fable Worker 从不 resume，而一个自定义名称能绕开下面按名称拦截的规则）。续跑一个已完成的 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`。Hook 看不到的一条路径：2.1.319 起 `/tasks` 有一行 "Earlier in this session"，列出已完成的 Subagent，用户可以重新打开并给它发消息，即使它已离开列表或会话重启过；这不是 `SendMessage` 工具调用，所以不经过 Hook。官方 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。在默认的 `onFailure: "continue"` 下，PreToolUse 的 exit 1 不会阻断，路径写错或脚本崩溃的 Hook 会放行一切。2.1.295 新增的 `onFailure: "block"` 是第二层：设置后，Hook 启动不了、超时、输出解析不了或不合 schema 的 JSON，或以 0 和 2 以外的码退出，PreToolUse 调用都会被阻断；因此每个 JSON 决定都必须以 exit 0 退出。但 2026-10-11 在 2.1.296 上实测，单靠它并不能让本机 Hook 在路径写错时 fail closed：探针里以 256 退出的 Hook 被当作成功、exit 1 则阻断，可见起作用的只是退出码的低字节；而 `powershell.exe -File <不存在的脚本>` 的退出码是 -196608（0xFFFD0000，低字节为 0），于是被记成 `hook_success`，调用照常执行。powershell.exe 本身启动成功，也不算文档里"启动不了"那一类。本机的 Hook 注册因此从 `-File` 改为 `-Command` 加一层包装：`& '<hook>.ps1'; if ($null -eq $LASTEXITCODE) { exit 1 }; exit $LASTEXITCODE`，再加 `"onFailure": "block"`。在 Claude Code 里端到端验证过：脚本缺失时调用被阻断（提示 `failed; blocking because onFailure is "block"`），脚本的 exit 2 原样透传、stderr 作为理由，exit 0 保留 JSON 决定。不加包装、只写 `-Command "& 'script'"` 时，脚本的 exit 2 会被变成 exit 1；2026-11-09 在 2.1.319 上复测，Windows PowerShell 5.1 仍是这样，2.1.309 与 2.1.316 的退出码修复只针对 `"shell": "powershell"` 形式的 Hook，所以包装保留。命令 Hook 的 `command` + `args` exec 形式自 2.1.139 起可用，hooks 文档对它不带版本限定。PreToolUse 除 allow、deny、ask 之外还有第四种结果 `defer`，多个 Hook 冲突时优先级是 `deny > defer > ask > allow`；不过 `defer` 只在 `-p` 非交互模式下生效，交互会话会记一条警告并忽略它，对本机这种交互 bypass 会话没有意义。另一条容易忽略的规则：`ask` 的 `permissionDecisionReason` 只显示给用户（只有 `-p` 下被自动拒绝时 Claude 才会在工具结果里读到它），`allow` 与 `defer` 的 reason 只进调试日志；要让 Claude 在放行后看到的说明必须放进 `additionalContext`，只有 `deny` 的 reason 会进入模型上下文。

Workflow 的 `agent()` 在没有指定 `model` 时运行在主会话模型上（workflows 文档原文："When nothing else assigns one, the agent runs on your session's model"）；effort 按会话的 effort 设置对这个模型解析；主会话是 Fable 时，缺 `model` 的 Agent 跑在 Fable 上，档位是 Fable 保存的档位（本机 2026-11-10 起为 medium），一个 fan-out 就会把整批 Agent 放到最贵的模型上。这句原文成立的前提是 2.1.296 新增的 `CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL` 未设置或为 `inherit`：它只见于 changelog，env-vars 文档没有收录，二进制显示它是强制值而不是兜底默认，一旦设置就丢掉每个 Workflow Agent 脚本里的 `model` 和 `agentType` 定义的模型（日志写 `Workflow agent model "..." ignored: CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL is set`），按角色路由随之失效，Hook 的模型检查也失去意义，所以本机保持不设。本机 Hook 因此读取 `tool_input.script`（或 `scriptPath`、按 `name` 匹配 `meta.name` 解析到的 Saved Workflow 文件。2.1.296 的加载器按脚本的 `meta.name` 而不是文件名登记 Saved Workflow，解析不出 meta 的脚本会被跳过，所以 Hook 也按 `meta.name` 查找，两个脚本声明同一名称时 `deny`。一次调用同时带 `script`、`scriptPath`、`name` 中的两个以上也 `deny`：SDK 参考与工具说明都写 `scriptPath` 优先，2026-10-11 实测 2.1.296 在 bypass 与 auto 两种会话里跑的却是内联脚本，Hook 无法确定实际运行哪一份。查找范围是工作目录到仓库根目录（第一个含 `.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`。Workflow 里的 effort 不做强制：它影响成本但不改变模型档位，脚本省略 effort 时 Agent 跑在会话 effort 设置对它自己模型解析出的档位上（实测 sonnet Agent 是 medium），那些设置由用户按项目决定。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 个，2026-10-11 补上 Fable 的 `effort` 与 `name`、多个脚本来源、`meta.name` 解析等用例后为 130 个）。实测在 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.322 的二进制里仍是运行时模板（与 2.1.267、2.1.270、2.1.280、2.1.282、2.1.296 文本只有运行时占位符不同，2.1.319 另多一处只在设置 `CLAUDE_CODE_SUBAGENT_EFFORT` 时渲染的 effort 条件句，2.1.321 与 2.1.322 的文本与 2.1.319 相同）：只有 `CLAUDE_CODE_SUBAGENT_MODEL_FORCE` 未设置、且 `CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL`（2.1.296+）未设置或为 `inherit` 时，才渲染 `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"）；在 Prompt 里打出 Workflow 关键词时注入的同样是内置文本，所以 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 保证。effort 方面，agent-teams 文档写明跑在 Lead 模型上的 Teammate 默认继承 Lead 的 effort（split-pane 模式自 2.1.186 起才生效），跑在其他模型上的用该模型保存的档位或默认值（2.1.317）；但由某个 Subagent 定义派生的 in-process Teammate 会按 frontmatter 规则使用该定义的 `effort`，in-process 正是默认显示模式（Windows Terminal 不支持 split pane），split-pane Teammate 的定义 effort 文档没有提。2.1.261 还修复了 in-process Teammate 第二轮重发首轮工具与 skill 声明、导致 prompt cache miss 的问题。这是保持 `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` 关闭、需要时先把 Lead 降到 high 再开 Team 的直接理由。没有角色定义的内置类型（general-purpose、Plan）没有定义级 effort：Agent 调用传了 `effort`（2.1.292+）就用它，未传时在主会话模型上继承会话档位、在其他模型上用该模型保存的档位或默认值；Hook 对它们返回 `ask`，在非 bypass 会话里形成人工确认。2.1.319 新增的 `permissions.denyInsteadOfPrompting` 会把等待权限提示的调用直接拒绝，设了它，Hook 的这些 `ask`（包括 SendMessage 的 `ask`）在会弹窗的会话里就变成拒绝；本机没有设。

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 结束回合这类重试也没用的失败直接暂停并说明原因，若会话正等待用量上限重置则到期自动续跑（2.1.314 起，没有用户 prompt 时自动续跑最多 3 次，`/goal` check-in 这类在两次等待之间自行重启的任务也不例外）；`CLAUDE_CODE_GOAL_CHECKIN_MINUTES=0` 会同时关闭自动重试与 check-in。

这里有两个独立的熔断器，之前的版本把它们混在了一起。Stop hook 的通用上限来自 hooks-guide：Stop hook 连续阻断 8 次、期间 Claude 没有任何工具调用时，Claude Code 会接管（2.1.296 文档的措辞是 "with no tool call from Claude in between"，hooks 文档补充计数在每次工具调用时清零），可用 `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 配置模板库](/blog/claude-code-agent-workflow-prompts/)，日常短 Prompt 集中放在[个人 Prompt Tips](/blog/personal-ai-agent-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 的会话级切换用 `/model` 选择器 Fable 行的 `s` 键或 `claude --model fable` 启动（直接输入 `/model fable` 会把它写成之后所有新会话的默认模型），2.1.321 起 `fable` 指 Fable 5.2，per-model 档位保存为 medium；定义里没有 `effort` 字段、Agent 调用也未传 `effort` 的 Worker 只在跑主会话模型时继承会话档位，其他模型用该模型保存的档位或默认值（2.1.317），`CLAUDE_CODE_SUBAGENT_EFFORT`（2.1.316）保持不设。用户设置文件里旧式的顶层 `effortLevel` 只适用于没有 per-model 条目的 Fable 5.1、Opus 5 及更早的模型（例如作为回退目标的 Opus 4.8、Sonnet 5），对 Opus 5.5 及之后发布的模型无效，包括 Sonnet 5.5、Haiku 5.5 与 Fable 5.2，它们默认都是 medium（model-config 与 settings-reference 写明这一点，条目按规范名匹配；2026-10-11 的探针也看到 Sonnet 5.5 主会话的 `effort.level` 是 medium）。它还能覆盖的那些模型本身默认就是 high，所以 2026-11-10 起删掉了顶层的 `effortLevel: high`，档位只写在 `modelSettings`：`claude-opus-5-5` 为 medium 并带 `autoCompactWindow: 400000`，`claude-fable-5-2` 为 medium。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.311 起在 `[1m]` 不起作用的模型上，模型名与 ID 会去掉这个后缀及其标签，写上仍被接受。另外自 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.2、`opus` 到 Opus 5.5，不在其列。

专用 coordinator Agent/profile 另行固定为 Opus/high。委派角色继续显式路由为 Explore Haiku/medium（搜索需要更多上下文或轮次时 Sonnet/medium）、planner/QA/reviewer Sonnet/high、implementer Opus/high、critical roles Fable/high。Codex 委派（包括 codex-rescue）计入同一账本，只在用户点名 Codex 时使用；插件自带的“主动使用”指引不覆盖这条规则。插件 1.0.6 的 `--effort` 只接受 `none` 到 `xhigh`，`codex-rescue` 默认以 `workspace-write` 和 `approvalPolicy: "never"` 运行；只需要 Codex 读代码时，在请求里写明 read-only。

每次派发显式指定角色模型，避免主会话默认值（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 的上下文成本与使用频次，下次清理应先跑它；skills 文档写的门槛是 v2.1.252，本文按 changelog 记版本。但本机 `DISABLE_TELEMETRY=1` 同时关闭了 feature-flag 拉取，env-vars 文档写明这会让 `/skill-doctor`、`claude import` 与 advisor 不可用，要跑它得临时去掉这个变量；2.1.319 新增的 `CLAUDE_CODE_DISABLE_FEATURE_FLAGS` 只关特性标志拉取、不关 telemetry，对必须关 telemetry 的本机没有区别；Monitor 工具（2.1.310）、`/auto-mode-setup`（2.1.304）、空闲压缩（2.1.314）与 MCP tasks（2.1.319）已不再依赖特性标志；Remote Control 自 2.1.283 起在只设了 `DISABLE_TELEMETRY` 或 `DO_NOT_TRACK` 时仍可用，除非组织要求 Trusted Devices），同时卸载了安装后从未启用的 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 工具的返回结果核对（`resolvedModel` 是启动时的模型，中途因 API 错误走回退链换了模型时只有 `modelsUsed` 会显示；2.1.318 起本机设置下被分类器标记的 Subagent 直接失败，不再换模型），`/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/` 目录](https://github.com/Dongshan-git/skills/blob/main/ds)，按 Claude Code 版本记录的变更日志见 [`ds/CHANGELOG.md`](https://github.com/Dongshan-git/skills/blob/main/ds/CHANGELOG.md)；之后每次 Claude Code 更新都会先复核再同步这几篇文章（2026-10-11 起是四篇）。2.1.283 新增的 `/doctor prompt-audit` 会检查 CLAUDE.md、rules、skills、commands、Subagent 等指令文件里为旧模型写的提示模式、指向不存在文件或命令的引用和相互矛盾的内容，只出报告与建议修改，不动文件，可以作为每轮复核的第一步。

**全局指令层**

- `~/.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`](https://github.com/Dongshan-git/skills/blob/main/ds/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，无法逐个指定。（2026-10-11 注：当前 agent-teams 文档写的是默认继承 Lead；由 Subagent 定义派生的 in-process Teammate 使用该定义的 `effort`，见第八节。）（2026-11-09 注：2.1.317 起只有跑在 Lead 模型上的 Teammate 继承 Lead 的 effort，其他模型用该模型保存的档位或默认值，见第十一轮。）

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

检索了 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 文档未写，手动重跑规则保留。（2026-10-11 注：model-config 现已写明 Subagent 里被标记的请求不弹提示、直接在回退模型上重跑，手动重跑只留给真正的 refusal，见第七节。）（2026-11-09 注：2.1.318 起在 "Ask each time" 下被标记的 Subagent 改为直接失败，Fable Worker 失败或 refusal 后在常规角色上以 Opus/high 重做一次，见第十一轮。）
- 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 时生效（2026-10-11 注：`haiku` 自 2.1.293 起指向支持 low 到 max 的 Haiku 5.5，该字段已改为 medium，见第九轮）；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 继承会话当时的档位（2026-10-11 注：实测是按会话 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（2026-10-11 注：`haiku` 改指 Haiku 5.5 后权重为 0.125，L2 示例为 2.625，见第九轮）。路由说明改为 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`（2026-10-11 注：Sonnet 5.5、Haiku 5.5 同样默认没有 Task 工具；除这个变量外，在 `--allowedTools` 里写出某个 Task 工具或在 `--tools` 里列出它也能开启，后台与云端会话在所有模型上都有）。
- 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` 的隐私对应项，直连时不省什么，暂不设。（2026-11-09 注：2.1.319 新增的 `CLAUDE_CODE_DISABLE_FEATURE_FLAGS` 可以只关特性标志、不关 telemetry，本机 telemetry 必须关，所以无关；Monitor、`/auto-mode-setup`、空闲压缩与 MCP tasks 已不再依赖特性标志，claude.ai skill 与插件同步、advisor、artifact 评论与 `/skill-doctor` 仍依赖，见第十一轮。）
- 驳回的一条：有发现认为"Fable refusal 改用 opus/xhigh 重做"在 Opus 5.5 上更糟。Opus 5 在 2.1.280 之前就带分类器、biology 直接 refusal，重做路径并没有变差，规则保留。（2026-11-09 注：重做档位已改为 opus/high，再被标记就报告用户，见第十一轮。）
- 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 项目协作操作规范》](/blog/claude-code-operating-rules/)。
- 文章事实修正：AGENTS.md 支持自 2.1.281 起在 telemetry 关闭的会话里也生效，不再随 feature-flag 拉取一起关掉；auto 模式的分类器审查自 2.1.282 起在 telemetry 关闭的会话里默认走服务端，`CLAUDE_CODE_AUTO_MODE_SERVER=0` 退回本地分类器请求；`attribution` 新增 `false` 简写，旧版本会整个跳过含它的设置文件，本机保持对象写法。（2026-11-09 注：2.1.319 起服务端检查不了的调用不再退回内置分类器，交互会话询问、Subagent 与 `-p` 拒绝，见第十一轮。）
- 与本文相关的 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 分钟。

**第九轮：2.1.296 复核（2026-10-11）**

2.1.296 于 2026-10-09 发布，本机已升级。2026-10-11 对照 2.1.283–2.1.296 的 changelog（14 个版本、1,248 行），并把全部 222 页官方文档按 markdown 重新下载，用一个 Workflow 跑：三个 Sonnet 读 changelog、四个审计者核对四篇文章、一个 Opus 审查配置，再由两个 Opus 做对抗式复核、一个 Opus 做完整性评审；90 条发现中 4 条驳回。剩下的开放问题用隔离的 `claude -p` 探针和一次会话内 Workflow 实测。从 2.1.296 二进制提取的 bundled `workflow-authoring` 文本与覆盖版只差文件头列出的策略段与运行时占位符；Hook 130 个用例全部通过。

- 模型与 effort：`sonnet` 自 2.1.284 起指向 Sonnet 5.5（每百万 token 输入 2 美元、输出 10 美元，2.1.296 起缓存读取 0.10 美元），`haiku` 自 2.1.293 起指向 Haiku 5.5（输入 0.10 美元、输出 0.50 美元，prompt 超过 100K token 时 0.50 美元与 2.50 美元，Anthropic API 上是 1M 上下文）。Opus 5.5、Sonnet 5.5、Haiku 5.5 默认都是 medium，用户设置文件里的顶层 `effortLevel` 对三者都无效；2.1.284 起 `/effort ultracode` 与 `ultracode` 设置不再改变 effort，只有 `--effort ultracode` 同时设为 xhigh。Opus 5.5、Sonnet 5.5、Haiku 5.5 与 Fable 5.1 在 effort 改变时保留 prompt cache（API key 或订阅，Bedrock、Agent Platform 与 apps gateway 除外）。
- Agent 工具：2.1.292 起非 fork 调用可以逐次传 `effort`，覆盖定义、resume 后保留，只低于 `CLAUDE_CODE_EFFORT_LEVEL`；能力边界表与第二节已改。Task 工具在 Sonnet 5.5、Haiku 5.5 上同样默认关闭，`--allowedTools` 或 `--tools` 写出 Task 工具也能开启。
- 分类器回退：model-config 现在写明 Subagent 里被标记的请求不弹提示、直接在回退模型上重跑，即使 `switchModelsOnFlag: false`；effort 保持（2.1.287）；Sonnet 5.5 的 cybersecurity 回退到 Sonnet 5，biology 直接 refusal。`resolvedModel` 仍写启动时的模型，只有 `modelsUsed` 暴露中途切换，第七节的规则据此改写。（2026-11-09 注：2.1.318 起在 "Ask each time" 下被标记的 Subagent 改为直接失败，`modelsUsed` 只来自 API 错误后的回退链，见第十一轮。）
- 其他事实：由定义派生的 in-process Teammate 使用定义里的 `effort`；Hook 的 `onFailure: "block"`（2.1.295）；`CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL`（2.1.296，只见于 changelog，二进制确认是强制值）；Remote Control 在只关 telemetry 时仍可用、`/doctor prompt-audit`（2.1.283）；Stop hook 上限的措辞改为"期间没有工具调用"；`allow` 的 reason 只进调试日志，不显示给用户。还纠正了一处长期错误：直接输入 `/model fable` 不是会话级切换，它会把 Fable 写成之后新会话的默认模型（2.1.287 的 changelog 也确认 claude.ai 登录下在 `/model` 选 Fable 会保存默认），会话级切换用选择器里的 `s` 键或 `claude --model fable`。
- T1：Agent 调用的 PreToolUse 输入在 `tool_input` 里带逐次的 `effort`（看到的键是 description、prompt、subagent_type、model、effort、run_in_background）；顶层的 `effort.level` 是调用方会话的档位，Sonnet 5.5 主会话是 medium，印证顶层 `effortLevel` 对 5.5 系列无效。
- T2：同时带 `script` 与 `scriptPath` 的 Workflow 调用，在 bypass 会话和 auto 模式的 `claude -p` 会话里跑的都是内联脚本，与 SDK 参考和工具说明里"`scriptPath` 优先"相反。Hook 本来就检查内联脚本，所以今天没有绕过，但契约与行为矛盾，Hook 改为拒绝同时带两个以上脚本来源的调用。
- T3：主会话 effort 为 xhigh 时，Workflow 里 `model: 'sonnet'`、不带 `effort` 的 Agent 跑在 medium（`CLAUDE_EFFORT=medium`），带 `effort: 'low'` 的跑在 low。不带定义级或逐次 effort 的 Worker 按会话 effort 设置对自己的模型解析，而不是跟随主会话当时的档位；Agent 工具派出的 general-purpose 这类内置类型按文档也是这样，没有单独测。
- T4（新发现）：`onFailure: "block"` 单独不能让本机 Hook 在路径写错时 fail closed。探针里以 256 退出的 Hook 被当作成功、exit 1 阻断；`powershell.exe -File <不存在的脚本>` 退出码为 -196608（0xFFFD0000，低字节 0），被记成 `hook_success`，调用照常执行。Hook 注册改为 `-Command` 包装（`if ($null -eq $LASTEXITCODE) { exit 1 }; exit $LASTEXITCODE`）加 `onFailure: "block"`，在 Claude Code 里端到端验证：脚本缺失被阻断，exit 2 原样透传，exit 0 保留 JSON 决定。不加包装的 `-Command "& 'script'"` 会把 exit 2 变成 exit 1。（2026-11-09 在 2.1.319 上复测仍成立，见第十一轮。）
- 用户决定：haiku 权重取 0.125（按超过 100K 的单价，不取基础单价的 0.025，也不沿用 Haiku 4.5 的 0.25），L2 示例由 3.25 改为 2.625；Explore 的 effort 从 low 改为 medium，因为 Haiku 4.5 上这个字段无效，Haiku 5.5 上它生效而默认是 medium，留着 low 等于给一个在没有它时验证过的角色计划外降档；非 Fable 角色可以逐次传 `effort` 作为同一角色上的第一步升档，Fable 角色的逐次 `effort` 与 `name` 都由 Hook 拒绝；文章继续写主会话是 `opus` 别名、Opus 5.5 固定 high。
- 配置改动：dispatch-policy 的权重、理由与升档段，`CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL` 保持不设或 `inherit`，Explore 行改为 haiku/medium，路由说明补上 5.5 系列默认 medium、ultracode 不再改 effort 与 T3，refusal 条目拆成文档化的 Subagent 回退与真正的 refusal 两条；`Explore.md` 改为 medium；`coordinator.md` 加入逐次 effort 升档（不用于 Fable 角色）与 `modelsUsed`；Hook 新增 Fable 的 `effort`/`name` 拒绝、多脚本来源拒绝、按 `meta.name` 解析 Saved Workflow 并拒绝重名，测试夹具改为临时会话目录，130 个用例通过；workflow-authoring 覆盖版版本行改为 2.1.296，并写明内置的 `model` 建议还要求 `CLAUDE_CODE_WORKFLOW_SUBAGENT_MODEL` 未设置或为 `inherit`、关键词触发同样注入内置文本；`settings.snippet.json` 与本机 `settings.json` 的 Hook 改为 `-Command` 包装加 `onFailure: "block"`。（2026-11-09 注：refusal 条目已按 2.1.318 改写，路由说明补上 2.1.317 的 effort 规则与保持不设的 `CLAUDE_CODE_SUBAGENT_EFFORT`，见第十一轮。）
- 记录但未改：`agent.spawn` mod 钩子（2.1.292 起覆盖 Workflow Agent）能改模型或拒绝派生，但不在 SendMessage resume 时运行，留到下一轮评估，与 Hook 重复；`/skill-doctor` 的版本门槛 changelog 写 2.1.261、skills 文档写 2.1.252，本文按 changelog。

**第十轮：2.1.300 配置检查（2026-10-15）**

本机已升级到 2.1.300（2.1.297 与 2.1.298 没有发布）。这一轮只检查 2.1.299 与 2.1.300 对配置的影响：读两版 changelog，重新下载 env-vars、settings-reference、sub-agents、model-config、prompt-caching、permission-modes 与 mods 各页，对比 2.1.296 与 2.1.300 二进制里的环境变量名，再用本机 2026-09-15 至 10-15 的会话记录（69 个主会话、2,424 次 Subagent 运行）量化。正文其余事实没有逐条复核。

- 空闲压缩：2.1.299 新增 idle compaction，20 万 token 以上的对话空闲约 54 分钟后、一小时缓存过期前自动压缩；`CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS` 改阈值（低于 10 万按 10 万算），`idleCompaction: false` 关闭。它的模式取自远程特性标志 `tengu_sunny_locket`，取不到时是 `off`。本机设了 `DISABLE_TELEMETRY=1`，特性标志拉取随之关闭（settings-reference 把"能拉取特性标志"列为条件之一），生产版二进制又去掉了本地覆盖标志的入口，所以这个变量和设置在本机都不起作用。本机所在内网明确规定不能开 telemetry，这条路不走。（2026-11-09 注：2.1.314 起内置空闲压缩在 telemetry 关闭时也运行，不再取特性标志，`tengu_sunny_locket` 已不存在，见第十一轮。）
- 数据：一个月里主会话在 10 万 token 以上空闲 60 分钟以上再回来共 137 次，其中 20 万以上 123 次；这些冷重建的缓存写入按 API 标价约 556 美元，而缓存还热时压缩一次估计不到 1 美元。
- 本地替代：mods API 不依赖特性标志（在空目录里运行 `claude plugin test` 报告 mod 可以加载），于是新增 `idle-compact` mod：主循环 `turn.complete` 后用 `$.clock.after` 定 54 分钟，主循环 `turn.start` 或 `session.end` 取消；到点时上下文不少于 20 万就调用 `$.session.compact()`。Subagent 与 Teammate 的回合带 `agentId`，用一个探针 mod 实测确认后忽略。验证了三层：`claude plugin validate`；7 个 mock 时钟单测；用 ConPTY 驱动一个交互会话，10 秒版测试副本真实压缩并写出日志行。`-p` 下同一调用被拒（"not available in a headless (-p / SDK) session yet"），所以只在交互会话生效。它经用户设置 `env` 里的 `CLAUDE_CODE_PLUGIN_DIRS`（2.1.280 起）加载，调试日志确认每个会话都带上。（2026-11-09 注：内置空闲压缩可用后，这个 mod 逻辑不变，保留为兜底，见第十一轮。）
- implementer 的压缩窗口：Subagent 继承顶层 `autoCompactWindow: 750000`。一个月里 735 次 implementer 运行有 98 次超过 30 万 token（最高 71.6 万），超过 30 万的请求 7,572 次，仅 30 万以上部分的缓存读取就约 171 美元。2.1.296 起定义可写 `autoCompactWindow`（只能调低），implementer 设为 300000。验证：用 `--agents` 定义一个 `autoCompactWindow: 100000` 的 Haiku Subagent，会话窗口仍是 75 万时，它在 `preTokens` 6.2 万处自动压缩，并原样保留最近 5.5 万 token；`--debug` 下 `200k` 报 invalid，`300000` 无告警。其他角色很少超过 30 万，不设。
- 记录但未改：压缩后不重发技能列表，2.1.299 的 `/reload-skills` 会重发；Hook 只返回 `deny`，2.1.300 对 `updatedInput` 的校验不影响它；telemetry 关闭时 auto 模式仍默认用服务端分类器；2.1.300 的请求 gzip 在走代理时跳过；2.1.300 起会话记录多存每次请求的系统提示与工具定义（本会话约占文件的 18%）；2.1.300 允许 `agent.spawn` mod 钩子改写或拒绝 Workflow Agent 的模型，以后可能替代 Hook 对脚本的词法检查，但事件字段没有文档，mods reference 仍写 SendMessage resume 时不触发，与 2.1.299 的 changelog 相反。（2026-11-09 注：2.1.304 起压缩会重发技能列表，`/reload-skills` 只发新增或改动的技能；2.1.319 起 telemetry 关闭时服务端检查不了的 auto 模式调用不再退回内置分类器，见第十一轮。）

**第十一轮：2.1.319 复核（2026-11-09）**

本机已升级到 2.1.319（2.1.313 与 2.1.315 没有发布）。这一轮对照 2.1.301–2.1.319 的 changelog，重新下载 settings-reference、env-vars、permissions、permission-modes、model-config、sub-agents、agent-teams、workflows、hooks、context-window 与 mods 等页面（几页落后于 changelog：env-vars 既没有 `CLAUDE_CODE_SUBAGENT_EFFORT` 也没有 `CLAUDE_CODE_DISABLE_FEATURE_FLAGS`，仍把 MCP tasks 列为依赖特性标志；permission-modes 仍写着退回本地分类器），检查 2.1.317–2.1.319 的二进制与 2026-10-15 以来的本机会话记录，再用两个 Sonnet 读取器把六篇文章与这些材料逐条比对。

- 分类器标记（2.1.318）：在 `switchModelsOnFlag: false`（"Ask each time"）下，Agent 工具派出的 Subagent 遇到被标记的请求不再在回退模型上重跑，而是以 `Agent terminated early due to an API error` 加 refusal 消息失败，由 Claude 决定怎么处理；此前不论选哪一项都会重跑。主会话照旧暂停询问，`-p` 照旧以 refusal 结束该轮。`modelsUsed` 因此只来自 API 错误后的回退链。Workflow Agent 与 Teammate 是否同样失败，文档没有写。第七节据此改写。
- Subagent effort（2.1.316、2.1.317）：没有自己 `effort` 的 Subagent 或 Teammate 只在跑主会话模型时继承会话档位，其他模型用该模型保存的档位或默认值，所以 Opus 主会话里不带 `effort` 的 `opus` Workflow Agent 跑在主会话档位上。新增的 `CLAUDE_CODE_SUBAGENT_EFFORT` 在 2.1.319 二进制里只在定义与调用都没写 effort 时生效，九个角色都写了 effort，保持不设。从 2.1.319 二进制提取的 bundled `workflow-authoring` 文本与覆盖版只差文件头列出的策略段，外加一处只在设了这个变量时渲染的条件句。
- 空闲压缩（2.1.314）：内置空闲压缩在 telemetry 关闭时也运行。2.1.319 的条件是交互会话（终端、VS Code 面板、桌面版 Code 标签页）、主线程一小时 prompt cache、`autoCompactEnabled`、`idleCompaction`（默认 true，2.1.302 起 `/config` 有这一行）、上下文不低于 `CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS`（默认 20 万，低于 10 万按 10 万算，本机不设），以及用量状态为 allowed（接近用量上限时不压缩）；不取远程特性标志，2.1.300 的 `tengu_sunny_locket` 已不存在。它在最后一次请求后缓存窗口的 0.9 处触发，通常早于 mod 在 `turn.complete` 时定下的 54 分钟，mod 到点时看到的已是压缩后的小上下文，什么也不做。会话记录：2.1.300–2.1.311 上 mod 压缩 35 次；2.1.314 起内置功能压缩 11 次（都在 2.1.318 上），mod 压缩 2 次，都发生在内置功能没有触发的空闲期（2.1.316 上一个 60.8 万 token 的会话，2.1.318 上一个 33.6 万 token 的会话），没有重复压缩。telemetry 关闭时看不到那两次内置功能为何没有触发，这正是保留兜底的理由；mod 不像内置功能那样在接近用量上限时收手。`-p` 会话两者都不覆盖。
- auto 模式（2.1.319）：telemetry 关闭时不再退回内置分类器，服务端检查不了的调用在交互会话里询问，在 Subagent 与 `-p` 里拒绝（`-p` 随后以 exit 1 结束，文本与 JSON 输出都是）；只有 `CLAUDE_CODE_AUTO_MODE_SERVER=0` 能保留本地分类器。本机走本地 HTTP 代理（`HTTP(S)_PROXY`，不是 `ANTHROPIC_BASE_URL` gateway），2026-11-09 的 `-p` 探针拿到了服务端判定，所以这个变量保持不设。不带 `--permission-mode` 的 `-p` 仍从设置里的 `defaultMode: auto` 启动（2.1.302 的默认模式变更只在没有配置模式时生效）；auto 模式会丢掉 `Bash(node:*)` 与 `PowerShell(node:*)` 两条 allow 规则（调试日志写 "bypasses classifier"）。
- 记录但未改：2.1.304 起压缩会重发技能列表，`/reload-skills` 只发新增或改动的技能，第十轮"压缩后不重发"的记录作废；Monitor（2.1.310）、`/auto-mode-setup`（2.1.304）与 MCP tasks（2.1.319，`CLAUDE_CODE_DISABLE_MCP_TASKS=1` 关闭）不再依赖特性标志，`CLAUDE_CODE_DISABLE_FEATURE_FLAGS`（2.1.319）因 telemetry 本来就关而无关；`permissions.denyInsteadOfPrompting`（2.1.319）与 `permissions.blockWritesOutsideWorkingDirectories`（2.1.314）不采用；`/tasks` 的 "Earlier in this session"（2.1.319）能重新打开已完成的 Subagent 并发消息，不经过 Hook；Hook 仍拒绝所有 fork；implementer 的 `autoCompactWindow: 300000` 不受 2.1.312 的影响，那次只改了它与 `CLAUDE_CODE_AUTO_COMPACT_WINDOW` 的交互，本机会话窗口来自设置键 `autoCompactWindow: 750000`；没有用户 prompt 时用量上限自动续跑最多 3 次（2.1.314）。
- 用户决定：`idle-compact` mod 保留，改称内置空闲压缩背后的兜底，逻辑不变；`switchModelsOnFlag: false` 保留，不让任何模型被静默替换，被标记的 Subagent 失败，被标记或 refusal 的 Fable Worker 在对应常规角色上以 opus/high 重做一次（原为 opus/xhigh），不再消耗 Fable 配额，再被标记就停下来报告用户；配置与文章在同一轮更新，不提交。
- 配置改动：dispatch-policy 的 effort 路由说明与 Fable 闸门最后两条；workflow-authoring 覆盖版的版本行改为 2.1.319，"Three facts" 一句补上 `CLAUDE_CODE_SUBAGENT_EFFORT` 的条件；`mods/idle-compact/hooks/register.js` 换成兜底说明的文件头注释（代码未改），`plugin.json` 升到 0.1.1 并改写描述；`ds/README.md` 与 `ds/CHANGELOG.md` 的 2.1.319 条目。`settings.json`（仍经 `CLAUDE_CODE_PLUGIN_DIRS` 加载 mod）、`settings.snippet.json`、全部 Agent 定义、Hook、coordinator profile 与 `CLAUDE.md` 不变。
- 验证：Hook 在 2.1.319 上 130 个用例全部通过，真实 Agent 调用按预期放行，带 `opus` 的 Explore 调用被拒；mod 的 `claude plugin validate` 与 7 个单测全部通过，2.1.319 生成的类型确认 Subagent 回合的 `turn.start` 带 `agentId`；auto 模式的 `-p` 探针如上；Windows PowerShell 5.1 在裸 `-Command "& 'script'"` 下仍把 exit 2 变成 1，`-Command` 包装保留，2.1.309 与 2.1.316 的退出码修复只针对 `"shell": "powershell"` 形式的 Hook。

**第十二轮：2.1.322 与选型指南复核（2026-11-10）**

本机已升级到 2.1.322（2.1.320 没有发布）。这一轮对照：

- 2.1.321–2.1.322 的 changelog
- Anthropic 的选型指南《Which Claude model should you build with》与 Fable 5.2 提示指南
- 当天下载的 model-config、settings-reference、sub-agents、pricing、prompt-caching 页面
- 2.1.321 与 2.1.322 的二进制，以及 2026-10-11 以来的本机主会话记录

- Fable 5.2（2.1.321）：`fable` 别名改指 Fable 5.2，每百万 token 输入 8 美元、输出 40 美元，缓存读取 0.20 美元；Max 上与之前的 Fable 一样最多占周额度 50%。`modelSettings` 按规范名匹配，原来的 `claude-fable-5-1: xhigh` 不再适用，Fable 会话悄悄落到 5.2 的默认 medium。dispatch-policy 的 fable 权重从 2.5 改为 2，关键角色同为 2。`reviewer-fable` 仍按 1，并标明这是从 Fable 5.1 沿用、尚未在 5.2 上实测的假设。第五、七节据此改写。
- 升档顺序：选型指南的顺序有三步：
  1. 先确认模型能验证自己的工作（测试、构建或调用接口的脚本）；
  2. 再升一级 effort；
  3. 最后换大一号模型，并从比小模型更低的档位起步。

  dispatch-policy 与 coordinator 定义改为这三步。关键 Fable 角色是第三步的例外，保持 high，理由有三：它们只接点名的难题；Hook 拒绝 Fable 角色的逐次 `effort`；Fable 5.2 提示指南说增益大多在 high 就已具备。两份官方材料给 Fable 5.2 的起点不一致：选型指南写"medium, then high"，提示指南写从 high 起步。第四节据此改写。

- 主会话档位与窗口：
  - 现状：2026-10-15 以来主会话 28,937 次请求里 28,891 次跑在 xhigh，其中 28,858 次 Opus 主线程请求按 API 标价约 3,104 美元。文中一直写的 Opus/high 早已漂移。
  - 档位：用户决定按指南把 Opus 5.5 存为 medium。Fable 5.2 也存为 medium（评审建议的是 high，用户选了 medium）。
  - 窗口：Opus 的 `autoCompactWindow` 单独降到 40 万。2026-10-11 以来 30,365 次 Opus 主线程请求中 11,266 次超过 40 万 token，峰值 71.7 万；40 万以上部分的缓存读取约 314 美元，这是节省的下限。顶层 75 万留给其他模型。
  - 验证：`--debug` 探针在 Opus 上记下 `effectiveWindow=380000`，`-p` 探针的请求带 `effort: medium`。
  - 顶层 `effortLevel: high` 删掉了。它在用户设置里只覆盖 Fable 5.1、Opus 5 及更早的模型，而这些模型默认就是 high，删掉不改变任何档位。
- 提前收尾：Fable 5.2 提示指南说模型在 low 与 medium 更容易在任务完成前结束回合，建议智能体工作在这两档加一段 Finishing work 提示。2.1.322 的二进制里已经有一段改写过的同类文字。`-p` 探针的会话记录显示，它出现在 Fable 5.2 的默认系统提示里，不出现在 Opus 5.5 主会话里，也不出现在以 coordinator 自定义提示运行的会话里。所以 Fable 主会话不用另加。`reviewer-fable` 与下面的 coordinator 实验用的是自定义提示，列为观察项。
- 待做实验（不改默认）：用 coordinator profile 加 `--model fable --effort medium` 跑一次 L3 任务。`-p` 探针确认会话跑在 Fable 5.2、effort medium、agent 为 coordinator；不加 `--effort` 时，profile 顶层的 high 对所有模型生效。依据与风险见操作规范文章规则 24。
- 撤回评审初稿的一条建议：把 qa 与 implementer 降到 medium。model-config 的 effort 表写"`high`: Work where verification matters or edge cases are likely, such as fixing a bug in an existing codebase"。qa、reviewer、implementer 正是这类工作，各角色档位不变。
- 本项目的验证命令：仓库 `CLAUDE.md` 新增 Verify your change 段。改 `content/**` 时只有 `pnpm build` 能编译 MDX，test、typecheck、lint 都覆盖不到，这正是指南升档顺序的第一步。
- 配置改动：
  - `settings.json` 的 `modelSettings`
  - dispatch-policy 的权重段、角色表的 reviewer-fable 行、升档段与 Fable 闸门两条
  - coordinator 定义的升档句
  - workflow-authoring 覆盖版的版本行：2.1.321 与 2.1.322 的 bundled 文本与 2.1.319 只差压缩后的标识符
  - `ds/README.md` 与 `ds/CHANGELOG.md` 的 2.1.322 条目

  Hook、mod、其余 Agent 定义、coordinator profile 与 `settings.snippet.json` 不变。

- 验证：
  - Hook 在 2.1.322 上 130 个用例全部通过（PowerShell 7），带 `opus` 的 Explore 调用被拒。
  - mod 的 `claude plugin validate` 与 7 个单测通过。
  - `CLAUDE_CODE_SUBAGENT_MODEL` 与 `ANTHROPIC_MODEL` 在进程、用户、机器三级环境变量与 shell 配置里都未设置。
  - Explore 仍是 haiku，主模型不是 `opusplan`。

## 结语

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

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

## 参考资料

- [Create custom subagents](https://code.claude.com/docs/en/sub-agents)
- [Dynamic agent workflows](https://code.claude.com/docs/en/workflows)
- [Agent teams](https://code.claude.com/docs/en/agent-teams)
- [How Claude remembers your project](https://code.claude.com/docs/en/memory)
- [Claude Code settings](https://code.claude.com/docs/en/settings)
- [All settings](https://code.claude.com/docs/en/settings-reference)
- [Environment variables](https://code.claude.com/docs/en/env-vars)
- [Claude Code permissions](https://code.claude.com/docs/en/permissions)
- [Extend Claude with skills](https://code.claude.com/docs/en/skills)
- [Model configuration](https://code.claude.com/docs/en/model-config)
- [Hooks reference](https://code.claude.com/docs/en/hooks)
- [Keep Claude working toward a goal](https://code.claude.com/docs/en/goal)
- [Hooks troubleshooting](https://code.claude.com/docs/en/hooks-guide#stop-hook-hits-the-block-cap)
- [Claude Code changelog](https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md)
- [Manage costs effectively](https://code.claude.com/docs/en/costs)
- [Monitor usage with OpenTelemetry](https://code.claude.com/docs/en/monitoring-usage)
- [Subagents in the Agent SDK](https://code.claude.com/docs/en/agent-sdk/subagents)
- [Agent SDK reference: TypeScript](https://code.claude.com/docs/en/agent-sdk/typescript)
- [Task budgets](https://platform.claude.com/docs/en/build-with-claude/task-budgets)
- [Claude prompting best practices](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices)
- [Prompting Claude Fable 5.1](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-1)
- [Prompting Claude Fable 5.2](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-2)
- [Which Claude model should you build with](https://claude.dev/blog/which-claude-model-should-you-build-with)
