# SubAgents

SubAgent 用于把一段独立任务委派给子 Agent。配置时要区分两个概念：

- `agentRole` 决定子 Agent 的行为、工具边界和提示词约束。
- `profile` 决定子 Agent 使用哪个运行时——DotCraft 原生运行时或外部 CLI。

如果只想让 DotCraft 安全地做一级委派，通常不需要改配置。默认设置已经允许根 Agent 创建一级 SubAgent，并阻止 SubAgent 再继续创建 SubAgent。

## 快速开始

默认配置等价于：

```json
{
  "SubAgent": {
    "MaxDepth": 1
  }
}
```

此时：

- 根 Agent 可以调用 `SpawnAgent` 创建一级 SubAgent。
- 一级 SubAgent 默认超过深度限制，不能再创建新的 SubAgent。
- `agentRole` 未指定时使用 `default`。
- 原生 SubAgent 默认使用轻量提示词 profile：`subagent-light`。

## 内置角色

| 角色 | 适合场景 | 工具策略 |
|---|---|---|
| `default` | 普通一级协作、总结、局部分析 | 禁用 AgentTools，使用保守工具集 |
| `worker` | 实现、验证、文件修改任务 | 允许读写、Shell、Web；AgentTools 仍受 `MaxDepth` 限制 |
| `explorer` | 只读代码探索、资料调研 | 只保留只读探索和 Web 工具，禁用写入、Shell、Plan/Todo、SkillManage、AgentTools |

`worker` 具备递归委派的能力模型，但默认 `SubAgent.MaxDepth = 1` 会阻止一级 SubAgent 再调用 `SpawnAgent`。这让递归 SubAgent 成为显式开启的高级选项。

## 配置

SubAgent 配置可以放在全局 `~/.craft/config.json` 或工作区 `<workspace>/.craft/config.json`。团队项目建议放在工作区配置中。

### 开启二级 worker 委派

```json
{
  "SubAgent": {
    "MaxDepth": 2
  }
}
```

开启后：

- 根 Agent 创建的第一级 `worker` SubAgent 可以看到 `SpawnAgent`。
- 第二级 SubAgent 到达深度上限，不能继续创建第三级 SubAgent。
- `default` 和 `explorer` 仍按各自 role 策略禁用 AgentTools。

### 覆盖内置 worker 说明

同名 role 会覆盖内置 role。下面示例保留 `worker` 的轻量提示词 profile，并为团队工作流添加说明：

```json
{
  "SubAgent": {
    "Roles": [
      {
        "Name": "worker",
        "Description": "Team worker role for bounded implementation tasks.",
        "AgentControlToolAccess": "Full",
        "PromptProfile": "subagent-light",
        "ToolDenyList": ["UpdateTodos", "TodoWrite", "CreatePlan"],
        "Instructions": "Complete the assigned task within the requested files. Summarize changed paths and validation results."
      }
    ]
  }
}
```

### 添加只读探索角色

```json
{
  "SubAgent": {
    "Roles": [
      {
        "Name": "docs-explorer",
        "Description": "Read-only documentation and code explorer.",
        "ToolAllowList": ["ReadFile", "GrepFiles", "FindFiles", "WebSearch", "WebFetch", "SkillView"],
        "AgentControlToolAccess": "Disabled",
        "PromptProfile": "subagent-light",
        "Instructions": "Inspect files and web sources only. Do not edit files, execute shell commands, manage skills, or spawn agents."
      }
    ]
  }
}
```

主 Agent 调用 `SpawnAgent` 时用 `agentPrompt` 传入任务内容，并把 `agentRole` 设为 `docs-explorer`。

### 使用完整提示词

原生 SubAgent 默认使用 `subagent-light`。如果某个 role 需要完整上下文，可改为 `full`：

```json
{
  "SubAgent": {
    "Roles": [
      {
        "Name": "full-context-worker",
        "Description": "Worker role with the full root prompt context.",
        "AgentControlToolAccess": "Disabled",
        "PromptProfile": "full",
        "Instructions": "Use the full project context to complete the assigned task."
      }
    ]
  }
}
```

## 轻量提示词

`subagent-light` 是原生 session-backed SubAgent 的默认提示词 profile。它保留：

- DotCraft 基础身份
- 当前 workspace 和环境信息
- role instructions
- 工具能力和限制
- `.craft/AGENTS.md`
- 必要的文件引用和工作风格

它默认跳过：

- Memory 全量上下文
- Skill self-learning 长说明
- custom commands 摘要
- deferred MCP discovery 长说明
- Plan / Todo 注入

这能让短任务 SubAgent 更快启动，也避免把主线程的长期上下文全部复制给子线程。

## Profile：选择运行时

`profile` 决定子 Agent 使用哪个运行时：

| Profile | 说明 |
|---|---|
| `native` | DotCraft 原生 SubAgent，支持 role-resolved 工具过滤 |
| `codex-cli` | 使用 Codex CLI 作为一次性外部 SubAgent |
| `cursor-cli` | 使用 Cursor CLI 作为一次性外部 SubAgent |
| `custom-cli-oneshot` | 模板 profile，需同名覆盖并补齐 `bin` 后才可用 |

DotCraft 会把 role instructions 传给外部 CLI，但不能强制过滤外部 CLI 自带工具。需要强隔离时优先使用 `native`，并结合 role allow/deny list 与 [安全配置](./security.md)。

---

## 使用外部 CLI 作为子代理

External CLI 子代理用于把已有 coding agent CLI 以短进程方式接入 DotCraft。相比 `native`，外部 CLI 通常只提供阶段级进度，不提供逐工具调用细节。

### 内置 Profile

| 名称 | runtime | 默认 `bin` | headless 入口 | 是否支持 resume |
|---|---|---|---|---|
| `native` | `native` | - | DotCraft 原生运行时 | 不适用 |
| `codex-cli` | `cli-oneshot` | `codex` | `codex exec` / `codex exec resume` | 支持 |
| `cursor-cli` | `cli-oneshot` | `cursor-agent` | `cursor-agent -p --output-format json --resume ...` | 支持 |
| `custom-cli-oneshot` | `cli-oneshot` | - | 模板 profile | 可选 |

当某个 `cli-oneshot` profile 的 `bin` 在本机不可解析时，DotCraft 会自动将其从系统提示词隐藏。

### 复用外部 CLI 会话

DotCraft 可以在同一线程里保存外部 CLI 的 session/chat/thread id，并在后续用户反馈时继续同一个外部会话。这个能力默认关闭，需在 Desktop 的 **Settings → Sub Agents** 中手动打开 `复用外部 CLI 会话`。

关闭时：

- 每次委派任务都会新建外部 CLI 会话
- 已保存的 session id 不会被删除，只是暂时不使用

### 何时会续接之前的会话

DotCraft 不会盲目复用任何旧会话，匹配规则：

- 优先按 `profile + label + workingDirectory` 精确匹配
- 没有 `label` 时，仅在同一 `profile + workingDirectory` 下唯一候选才自动续接
- 其余情况一律新建会话

希望主 Agent 在"第一次委派 → 用户反馈 → 再次委派"之间继续同一个外部 CLI 会话时，最稳妥的方式是：

- 复用同一个 profile
- 复用同一个 label
- 保持相同工作目录

### 自定义外部 CLI Profile

子代理配置位于 `config.json` 的 `SubAgentProfiles`。工作区配置覆盖同名全局 profile。

```json
{
  "SubAgent": {
    "EnableExternalCliSessionResume": true
  },
  "SubAgentProfiles": {
    "my-cli": {
      "runtime": "cli-oneshot",
      "bin": "my-cli",
      "workingDirectoryMode": "workspace",
      "inputMode": "arg",
      "outputFormat": "text",
      "supportsResume": true,
      "resumeArgTemplate": "--resume {sessionId}",
      "resumeSessionIdJsonPath": "session_id"
    }
  }
}
```

### 字段参考

| 字段 | 说明 |
|---|---|
| `runtime` | 运行时类型；外部短进程 CLI 使用 `cli-oneshot` |
| `bin` | CLI 可执行文件名或绝对路径 |
| `args` | 固定参数列表 |
| `workingDirectoryMode` | `workspace` / `specified` |
| `inputMode` | `stdin` / `arg` / `arg-template` / `env` |
| `inputArgTemplate` | `arg-template` 模式的模板 |
| `inputEnvKey` | `env` 模式写入任务文本的环境变量名 |
| `env` | 固定注入到子进程的环境变量 |
| `envPassthrough` | 从父进程复制的环境变量名列表 |
| `outputFormat` | `text` 或 `json` |
| `outputJsonPath` | `json` 模式下提取最终结果的路径 |
| `readOutputFile` | 是否优先读取输出文件作为最终结果 |
| `outputFileArgTemplate` | 输出文件参数模板，支持 `{path}` |
| `supportsResume` | 是否允许 DotCraft 保存并复用外部 session id |
| `resumeArgTemplate` | resume 参数模板，支持 `{sessionId}` |
| `resumeSessionIdJsonPath` | 从 stdout JSON 提取 session id 的路径 |
| `resumeSessionIdRegex` | stdout 不是单个 JSON 对象时用正则提取 session id |
| `timeout` | 单次运行超时秒数 |
| `maxOutputBytes` | 最大捕获输出字节数 |
| `trustLevel` | 信任等级：`trusted` / `prompt` / `restricted` |
| `permissionModeMapping` | DotCraft 审批模式到 CLI 参数的映射 |

`supportsResume = true` 时必须配置：

- `resumeArgTemplate`
- `resumeSessionIdJsonPath` 或 `resumeSessionIdRegex` 至少一个

### 审批与权限穿透

**Native 子代理**

- Native 子代理内部的 `ReadFile/WriteFile/Exec` 会复用当前会话的 `IApprovalService`
- 审批请求会在 command/path 前自动加上前缀：`[subagent:<label>] ...`

**External CLI 子代理**

- DotCraft 不拦截外部 CLI 内部工具调用，而是把当前审批模式翻译为启动参数
- 映射入口是 profile 的 `permissionModeMapping`
- resume 参数会插在审批参数之前，但仍由 DotCraft 决定是否允许 resume

### 厂商 Headless 参考

**`cursor-cli`** — DotCraft 内置基础参数 `-p --output-format json`，需要续接时追加 `--resume {sessionId}`。

**`codex-cli`** — DotCraft 内置基础参数 `exec`，并通过输出文件参数补上 `--skip-git-repo-check --json --output-last-message {path}`。需要续接时改为 `exec resume {sessionId}`；interactive / restricted 模式默认附加 `--sandbox read-only`，auto-approve 模式默认附加 `--dangerously-bypass-approvals-and-sandbox`。session id 从 stdout 中的 `thread_id` 提取。

## 字段参考

完整字段表见 [配置完整参考](../developing/configuration.md#subagent)。

## 相关入口

- [项目级工作区](./workspace.md)
- [安全与沙箱](./security.md) — 用工作区边界、沙箱限制 SubAgent 行为
- [可观测性](./observability.md) — 在 Dashboard 看 SubAgent 调用与审批
