子代理
子代理(subagent)是主代理可以委派任务的、拥有全新上下文的专注助手。每个子代理是你工作区 .claude/agents 目录下的一个 markdown 文件:文件的 frontmatter 决定子代理使用哪个模型、哪些工具,正文则成为子代理的系统提示。本页讲的是编写这些定义——如何运行后台或恢复代理,请看 /guide/background-tasks。
文件契约
.claude/agents 下的每个文件就是一个代理定义。文件正文(frontmatter 之后的所有内容)是代理的系统提示——即它的人设和指令。YAML frontmatter 控制调度行为。
.claude/
agents/
reviewer.md
debugger.md发现机制以会话的工作目录为准,而不是宿主进程的 cwd——因此即使 harness 从别处启动,这些定义依然可见。用户层和项目层都会加载,项目层覆盖用户层。
Frontmatter 字段
只有加载器真正消费的字段:
| 字段 | 作用 |
|---|---|
description | 一句话说明该代理的用途。Available subagents 系统提示区块渲染的就是它,因此它驱动调度——主模型靠阅读这些描述来挑选代理。 |
model | Claude Code 风格的模型别名(sonnet、opus、haiku、fable、inherit 等)。在 spawn 时通过 ccModelRoutes 服务解析,见 /guide/model-routing。 |
tools | 收窄子代理的工具集(allow/deny),见下文工具一节。 |
background | 将该代理固定为可继续的后台代理启动,见下文。 |
isolation | isolation: worktree 会把子代理调度进它自己的 git worktree,见下文。 |
ephemeral | ephemeral: true 让任何定义强制走前台一次性通道;ephemeral: false 覆盖只读白名单。见下文"临时只读代理"一节。 |
ephemeralTtlMs | 运行中临时子代理的 TTL(毫秒),默认 15 分钟。见下文"临时只读代理"一节。 |
autoReleaseMs | 自然结束后自动释放窗口的覆盖值(毫秒);0 表示永不自动释放,非法值在加载时大声失败。见下文"自然结束后的自动释放"一节。 |
加载器也会解析 permissionMode、memory、effort 等 CC frontmatter 字段,但 v1 不会把它们投影到子代理上——使用了这些字段的定义,其行为等同于字段不存在。(isolation: worktree 和 background: true 是会被消费的,见下文。)
省略的字段有合理的回退:省略 model 则继承父代理的路由;省略 tools 则子代理获得完整的父级工具视图。
最小示例
---
description: Fast codebase lookups
model: haiku
---
You are a read-only codebase scout. Return paths and line numbers,
not implementations.上面的正文会作为子代理的系统提示交付;委派时传入的任务文本则成为子代理的第一条用户消息。
调度
主代理通过 Task 工具委派,把代理名作为 subagent_type 传入。会话的系统提示会渲染一个 Available subagents 区块,列出工作区中的文件定义,例如:
## Available subagents
- explore — a fast, read-only codebase scout; returns paths and line numbers, not implementations
- dsh-cc-guide — answers questions about dsh-cc itself: commands, tools, settings, known limits
To delegate to one, pass its name as the `subagent_type` argument of the Task tool.区块列出工作区文件定义,以及插件挂载的代理(后者以限定 id plugin:agent 呈现)——后端 provider 名称永远不会被当作可寻址的类型展示。
调度分五种情况:
subagent_type省略、为空或为general-purpose—— 对调用者做一次全新 spawn:提示文本成为子代理的第一条用户消息,不参与任何定义,也不复制父对话。请写自包含的提示。subagent_type: "fork"—— 对调用者做一次继承对话的 fork:已完成的父轮次作为子代理的种子;不参与任何定义。fork是保留哨兵,优先于同名的工作区文件,因此.claude/agents/fork.md不可达。- 匹配到工作区中的某个定义 —— spawn 的人设是该定义的正文,模型路由是别名解析后的
model:,工具按经过清洗的tools:值过滤。子代理的最大委派深度为 3。 - 匹配插件代理的限定 id
plugin:agent—— 按与工作区定义完全相同的方式折叠(人设、清洗后的工具、别名解析的模型、最大深度 3、后台固定)。插件代理只能通过限定 id 寻址——裸插件代理名不可寻址,与 Claude Code 一致。文件定义与限定 id 占据不相交的命名空间:agentType含:的工作区文件会在发现时被跳过并告警。 - 其他任何类型 —— 返回错误结果,列出该工作区可用的类型(或说明工作区没有定义);类型包含
:时会附带相应提示。
内置代理
除工作区自定义的定义外,cc 预设还内置两个代理:
| 代理 | 说明 |
|---|---|
explore | 快速、只读的代码库侦察。连接 Serena MCP 服务器后,它还携带只读的符号检索工具(mcp__serena__find_symbol、mcp__serena__find_referencing_symbols、mcp__serena__get_symbols_overview)。 |
dsh-cc-guide | 解答关于 dsh-cc 本身的问题——命令、工具、设置、已知限制。 |
行为控制
model: 与别名路由
frontmatter 的 model: 字段在每次 spawn 时都通过 ccModelRoutes 解析,因此 model: haiku 会落到你的 haiku 路由当时映射到的 provider/model——重新映射某个路由无需改动定义。若别名服务不存在,所有子代理直接继承父代理的路由。细节与示例见 /guide/model-routing。
tools: 限制
frontmatter 的 tools: 值会收窄子代理的工具集,并针对 spawn 时实际注册的工具做清洗:
- 注册表不认识的名称会被丢弃并告警——包括未挂载服务器的 MCP 工具。
mcp__<server>__<tool>条目按原样保留,必须使用工具的公开名称;mcp__<server>和mcp__<server>__*会展开为该服务器已挂载的全部工具。不带服务器段的裸mcp__作为非法通配符被丢弃。- allow 列表匹配不到任何名称时会大声报错:如果清洗后一个名称都不剩,子代理将以零工具运行(并告警),因为完全省略
allow反而会把子代理放宽到所有工具。 - 尚处于延迟注册状态的显式
tools:条目会在子代理启动前被预加载;服务器级通配符只用于限制,从不预加载。
background: true
默认情况下 Task 调用是前台的:工具等待子代理完成并返回其文本输出。在定义中设置 background: true 会把该代理固定为持久、可继续的后台代理——调用立即返回一个 agentId,结果稍后以唤醒消息的形式到达。调用方仍可覆盖这一固定:显式 run_in_background: false 强制前台,显式 run_in_background: true 则让任何代理都在后台启动。
后台代理的运行、恢复、中断与查看(send_message / interrupt / list、/tasks、/agents)见 /guide/background-tasks。
临时只读代理
白名单中的只读定义——内置的 explore 与 dsh-cc-guide,以及 dsh-cc-shunt 插件的 shunt-reader——外加任何在 frontmatter 中显式声明 ephemeral: true 的定义,都会以前台一次性的方式运行:一次普通 spawn,不创建持久子代理、不写恢复钉版、不可恢复。定义上的 ephemeral: false 会覆盖白名单。
上面的后台化控制不会延续到这一通道:这类定义上的 background: true 固定会被忽略(并附一条显式提示,说明固定被忽略是因为只读临时代理永远以前台一次性方式运行);显式的 run_in_background: true 参数会被快速失败拒绝;isolation: worktree 以同样方式被拒绝;Ctrl+B 无法提升临时代理的等待;每条临时代理的结果都带有一行提示,说明没有创建持久子代理。
运行中的临时子代理按定义的 ephemeralTtlMs 或 15 分钟默认值收割;到期会提示 "ephemeral child hit its TTL; re-spawn it"。运行中的临时子代理计入 25 个存活子代理的容量护栏;对运行中的临时代理不支持 release_agent(按模式门控)——它只能自己结束,或撞上 TTL。
自然结束后的自动释放
自然结束的可持续子代理会在一段不活跃宽限期后被自动释放:前台送达的结果为 30 分钟,后台送达的结果为 2 小时(包括 Ctrl+B 提升后的唤醒消息)。
按定义覆盖的旋钮是 frontmatter 的 autoReleaseMs(毫秒):缺省使用层级默认值,0 表示永不自动释放,非法值在加载时大声失败。dsh-cc-agents 插件的写通道代理在其定义中固定了 autoReleaseMs: 7200000——等于 2 小时的后台默认值,显式固定是为了让它不受策略漂移影响。
结束时的消息会在两个送达点都标明该窗口("auto-released after … of inactivity"),被自动释放的子代理在 /agents 中的标记与手动释放的完全相同。自动释放后该子代理无法继续——send_message 会被拒绝,与手动 release_agent 同一条规则;release_agent 仍然是用来处理卡死的 RUNNING 子代理(可以丢弃的那种)的工具。
isolation: worktree
frontmatter 中标记 isolation: worktree 的定义,其子代理会被调度进一个专属的 git worktree,而不是父目录树:
- 创建——在
<mainRepoRoot>/.claude/worktrees/subagent-<childId>下、worktree-subagent-<childId>分支上创建 worktree,走的是与EnterWorktree相同的加固路径(公共目录根定位、local-config 扫描、filter-driver 中和;LFS 内容以指针文件形式到达),并在运行期间加锁。任何创建失败都会拒绝本次调度——子代理绝不会悄悄回落到父目录树。 - 接管——子代理的第一个步骤会把它的会话 cwd 移入 worktree;同时向人设追加一段契约说明,并在提示的第一行前置一条提示。
- 清理——
subagent/end时会探测工作区是否有未提交改动、以及是否有超出记录基线 HEAD 的提交。干净且无提交 → worktree 解锁并连同分支一起删除;否则该树会留在磁盘上,并在子代理的最终输出中说明这一点。
如实说明限制(该功能是部分的):子代理的 header.cwd、harness 沙箱根和 bash 默认工作目录仍沿用父级的;当约定目录无法落入沙箱根时(父 cwd 在仓库根的子目录下),调度会被拒绝;被委派的子代理无法回应审批提示,沙箱拒绝的写入会直接硬失败;Serena(用户自行挂载)固定一个项目根,不会跟随子代理。文件格式见 /reference/extension-formats;启动器与会话内 worktree 生命周期见 /guide/worktrees。
Actor-contract 区块
定义可以把正文的一部分包在 <!-- actor-contract:start --> … <!-- actor-contract:end --> 标记行之间。只有当子代理解析出的模型 id 匹配 actor-contract 设置命名空间中 models 的某个模式时(默认 ['glm-*'],大小写不敏感),该区块才会进入子代理的系统提示。[] 表示禁用,['*'] 表示对所有模型生效。model: 未设置(继承)的定义按 fail-closed 处理:区块被剥离。标记行本身永远不会进入提示。典型用途:插件自带的代理中针对特定模型的证据或契约段落。
说明与限制
截至 dsh-cc v0.6.0:
/agents是部分的。 它只是对运行中代理的瘦快照(列表/详情/停止/释放);分组只有驻留状态,/agentsattach 是保留但未实现的命名空间。- 进程级发现缓存。 定义按工作区根在进程生命周期内缓存,且不监听文件系统:对于尚未建立缓存的条目,编辑在下一个会话生效;否则需重启进程。
- 冷恢复按钉版恢复。 后台子代理的人设、工具过滤、模型路由和
maxTokens都从恢复钉版还原——钉版中记录为未设置的推理力度或 token 字段按缺失处理,而不是重新解析。其他代理选项在恢复后不保留。 - 没有 TaskOutput 别名,也没有 outputFile 字段。 前台结果以文本返回,没有输出文件。
- Task 子代理会剥离工作区指令。 与 Claude Code 的自定义子代理不同,被委派的子代理在其可见批次中不会收到工作区
CLAUDE.md/AGENTS.md基线(fork 子代理仍继承父种子中已有的内容)。
大体量子代理产物:handoff 存储
子代理可以用 handoff_put 把长报告或计划放进 handoff 存储,并返回一段嵌有 handoff://<id> 句柄的简短摘要(≤2 KB 左右为宜);编排方或后续子代理用 handoff_get 解析该句柄。值得知道的事实:
- 句柄只在 cwd 哈希到相同 projectKey 的会话间解析——同一仓库的另一个 git worktree 是不同的 key。
- 保留策略为 24 小时 TTL,外加每个项目一个 500 条目的磁盘 LRU。
- 设置命名空间
cc-handoff:enabled(默认true)与threshold-chars(8192,仅作提示,从不强制)。
下一步
- /guide/worktrees —— 围绕 git worktree 的启动器参数、会话内工具与子代理隔离。
- /guide/background-tasks —— 运行、恢复和中断后台代理。
- /guide/skills ——
SKILL.md技能,另一种扩展面。 - /reference/extension-formats —— dsh-cc 读取的文件格式,包括
.claude/agents。