Skip to content

子代理 ​

子代理(subagent)是主代理可以委派任务的、拥有全新上下文的专注助手。每个子代理是你工作区 .claude/agents 目录下的一个 markdown 文件:文件的 frontmatter 决定子代理使用哪个模型、哪些工具,正文则成为子代理的系统提示。本页讲的是编写这些定义——如何运行后台或恢复代理,请看 /guide/background-tasks。

文件契约 ​

.claude/agents 下的每个文件就是一个代理定义。文件正文(frontmatter 之后的所有内容)是代理的系统提示——即它的人设和指令。YAML frontmatter 控制调度行为。

text
.claude/
  agents/
    reviewer.md
    debugger.md

发现机制以会话的工作目录为准,而不是宿主进程的 cwd——因此即使 harness 从别处启动,这些定义依然可见。用户层和项目层都会加载,项目层覆盖用户层。

Frontmatter 字段 ​

只有加载器真正消费的字段:

字段作用
description一句话说明该代理的用途。Available subagents 系统提示区块渲染的就是它,因此它驱动调度——主模型靠阅读这些描述来挑选代理。
modelClaude Code 风格的模型别名(sonnet、opus、haiku、fable、inherit 等)。在 spawn 时通过 ccModelRoutes 服务解析,见 /guide/model-routing。
tools收窄子代理的工具集(allow/deny),见下文工具一节。
background将该代理固定为可继续的后台代理启动,见下文。
isolationisolation: worktree 会把子代理调度进它自己的 git worktree,见下文。
ephemeralephemeral: true 让任何定义强制走前台一次性通道;ephemeral: false 覆盖只读白名单。见下文"临时只读代理"一节。
ephemeralTtlMs运行中临时子代理的 TTL(毫秒),默认 15 分钟。见下文"临时只读代理"一节。
autoReleaseMs自然结束后自动释放窗口的覆盖值(毫秒);0 表示永不自动释放,非法值在加载时大声失败。见下文"自然结束后的自动释放"一节。

加载器也会解析 permissionMode、memory、effort 等 CC frontmatter 字段,但 v1 不会把它们投影到子代理上——使用了这些字段的定义,其行为等同于字段不存在。(isolation: worktree 和 background: true 是会被消费的,见下文。)

省略的字段有合理的回退:省略 model 则继承父代理的路由;省略 tools 则子代理获得完整的父级工具视图。

最小示例 ​

markdown
---
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 区块,列出工作区中的文件定义,例如:

text
## 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 名称永远不会被当作可寻址的类型展示。

调度分五种情况:

  1. subagent_type 省略、为空或为 general-purpose —— 对调用者做一次全新 spawn:提示文本成为子代理的第一条用户消息,不参与任何定义,也不复制父对话。请写自包含的提示。
  2. subagent_type: "fork" —— 对调用者做一次继承对话的 fork:已完成的父轮次作为子代理的种子;不参与任何定义。fork 是保留哨兵,优先于同名的工作区文件,因此 .claude/agents/fork.md 不可达。
  3. 匹配到工作区中的某个定义 —— spawn 的人设是该定义的正文,模型路由是别名解析后的 model:,工具按经过清洗的 tools: 值过滤。子代理的最大委派深度为 3。
  4. 匹配插件代理的限定 id plugin:agent —— 按与工作区定义完全相同的方式折叠(人设、清洗后的工具、别名解析的模型、最大深度 3、后台固定)。插件代理只能通过限定 id 寻址——裸插件代理名不可寻址,与 Claude Code 一致。文件定义与限定 id 占据不相交的命名空间:agentType 含 : 的工作区文件会在发现时被跳过并告警。
  5. 其他任何类型 —— 返回错误结果,列出该工作区可用的类型(或说明工作区没有定义);类型包含 : 时会附带相应提示。

内置代理 ​

除工作区自定义的定义外,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,而不是父目录树:

  1. 创建——在 <mainRepoRoot>/.claude/worktrees/subagent-<childId> 下、worktree-subagent-<childId> 分支上创建 worktree,走的是与 EnterWorktree 相同的加固路径(公共目录根定位、local-config 扫描、filter-driver 中和;LFS 内容以指针文件形式到达),并在运行期间加锁。任何创建失败都会拒绝本次调度——子代理绝不会悄悄回落到父目录树。
  2. 接管——子代理的第一个步骤会把它的会话 cwd 移入 worktree;同时向人设追加一段契约说明,并在提示的第一行前置一条提示。
  3. 清理——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 是部分的。 它只是对运行中代理的瘦快照(列表/详情/停止/释放);分组只有驻留状态,/agents attach 是保留但未实现的命名空间。
  • 进程级发现缓存。 定义按工作区根在进程生命周期内缓存,且不监听文件系统:对于尚未建立缓存的条目,编辑在下一个会话生效;否则需重启进程。
  • 冷恢复按钉版恢复。 后台子代理的人设、工具过滤、模型路由和 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,仅作提示,从不强制)。

下一步 ​

dsh-cc 不是 Claude Code,也不是 Claude Code 的包装器。与 Anthropic 无关联,亦未获其背书。