Skip to main content
Glama
README.md
# cc-agent-router

> 为 Claude Code 按任务角色路由不同 API、凭据与模型,同时保留你已经配置好的 MCP、Skill、Plugin、hooks、memory 和项目 `CLAUDE.md`。

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22.12-339933?logo=node.js&logoColor=white)](package.json)
[![TypeScript](https://img.shields.io/badge/TypeScript-ESM-3178C6?logo=typescript&logoColor=white)](tsconfig.json)

`cc-agent-router` 是一个面向 Claude Code 的多 provider / 多模型子代理路由器。它让主 Claude 可以把调研、设计、实现、审查和测试交给不同角色,每个角色使用独立的 API、API key、base URL、model 和权限策略。

项目提供三种接入方式:

- **Claude Code Plugin(推荐)**:MCP 负责执行,Skill 负责告诉 Claude 何时和如何委派;
- **CLI**:手动列出角色、运行代理、打开可见终端、导入 CC Switch;
- **Node API**:嵌入自定义编排器。

如果只想尽快跑起来,请先看 **[快速使用教程](QUICKSTART.md)**。

---

## 目录

- [为什么需要它](#为什么需要它)
- [核心能力](#核心能力)
- [工作原理](#工作原理)
- [要求](#要求)
- [安装](#安装)
- [配置](#配置)
- [从 CC Switch 导入](#从-cc-switch-导入)
- [CLI 使用](#cli-使用)
- [安装为 Claude Code Plugin](#安装为-claude-code-plugin)
- [仅配置 MCP](#仅配置-mcp)
- [headless 与 terminal](#headless-与-terminal)
- [配置继承与隔离边界](#配置继承与隔离边界)
- [权限与安全](#权限与安全)
- [Node API](#node-api)
- [故障排查](#故障排查)
- [开发与测试](#开发与测试)
- [设计来源](#设计来源)
- [当前限制](#当前限制)
- [开源协议](#开源协议)

---

## 为什么需要它

CC Switch 的 provider 切换适合改变“当前 Claude Code 使用哪个 API”,但如果多个子代理同时工作,反复覆写同一份 live 配置会带来竞态:

```text
主 Claude
├── research  想用 API A / 模型 A
├── implement 想用 API B / 模型 B
└── review    想用 API C / 模型 C
```

若三个进程共享同一个正在被覆写的 provider 配置,就可能出现凭据或模型串用。

`cc-agent-router` 不修改当前用户的 live provider 配置。每次调用都创建独立进程,并只在该进程环境里注入目标 provider 的:

- `ANTHROPIC_BASE_URL`;
- `ANTHROPIC_API_KEY` 或 `ANTHROPIC_AUTH_TOKEN`;
- 该 provider 明确声明的其他环境变量;
- 角色指定的 model、tools、permission 和 prompt。

与此同时,它**不会使用 `--bare`,也不会另建空白 `CLAUDE_CONFIG_DIR`**,所以子代理能继续使用你现有的 Claude Code 工具配置。

---

## 核心能力

- 按 `role → provider → model` 路由任务;
- 不同角色使用不同 API key 和 base URL;
- 多个角色可以并发运行,不覆写用户当前 Claude Code 配置;
- 继承现有 MCP、Skill、Plugin、hooks、memory、用户设置及项目 `CLAUDE.md`;
- 支持 `headless` 后台执行并把结果返回主代理;
- 支持 `terminal` 打开独立可见窗口,让用户实时观察和继续交互;
- 支持用户指定运行文件目录,目录不存在时自动创建;
- 支持从 CC Switch SQLite 数据库只读导入 provider/model;
- CC Switch 凭据不会复制进路由 YAML,每次运行读取最新值;
- 支持 CLI、stdio MCP server、Claude Code Plugin 和 Node API;
- API key 不进入 prompt、命令行、YAML 或返回结果;
- 对子进程输出中的已知凭据执行脱敏;
- 默认仅继承必要环境变量,降低无关业务 secret 泄漏风险;
- Windows 超时终止整个进程树,POSIX 终止独立进程组。

---

## 工作原理

```text
┌─────────────────────────────┐
│ 主 Claude Code              │
│ 已有 MCP / Skill / Plugin   │
└──────────────┬──────────────┘
               │ MCP delegate(role, prompt)
               ▼
┌─────────────────────────────┐
│ cc-agent-router             │
│ 1. 解析 role                │
│ 2. 解析 provider/model      │
│ 3. 读取目标凭据             │
│ 4. 构造最小子进程环境       │
└──────┬──────────┬───────────┘
       │          │
       ▼          ▼
  headless      terminal
  后台 JSON     新可见窗口
       │          │
       ▼          ▼
 Claude Code   Claude Code
 API A/model A API B/model B
```

### Provider 与 Agent 分层

```yaml
providers:
  api-a:
    baseUrl: https://api-a.example.com
    authTokenEnv: API_A_KEY

agents:
  research:
    provider: api-a
    model: model-a
    permissionMode: plan
```

- **provider** 管连接方式和凭据来源;
- **agent/role** 管 model、工具、权限、预算和任务用途;
- 同一 provider 可对应多个模型角色;
- 同一模型也可因权限或 system prompt 不同而配置多个角色。

---

## 要求

- Node.js `22.12.0` 或更高版本;
- Claude Code CLI,且 `claude --version` 可运行;
- 目标 provider 能接受 Claude Code 使用的 Anthropic Messages API;
- 使用 CC Switch 导入功能时,需要系统中有 `python` 和标准库 `sqlite3`;
- Windows 可见终端默认优先使用 Windows Terminal,缺少时自动回退到 PowerShell。

检查环境:

```bash
node --version
claude --version
python --version
```

---

## 安装

### 从源码安装

```bash
git clone https://github.com/CjQkJ/cc-agent-router.git
cd cc-agent-router
npm install
npm run build
```

直接使用构建后的 CLI:

```bash
node dist/cli.js --help
```

可选:注册全局命令:

```bash
npm link
ccar --help
```

`cc-agent-router` 和 `ccar` 是同一个 CLI 的两个命令名。

> 目前仓库提供源码安装。若未来发布到 npm,可改用 `npm install -g cc-agent-router`。

---

## 配置

生成示例:

```bash
ccar init
```

或不使用全局 link:

```bash
node dist/cli.js init
```

默认生成:

```text
cc-agent-router.yaml
```

### 配置查找顺序

1. CLI `--config <path>`;
2. 环境变量 `CC_AGENT_ROUTER_CONFIG`;
3. 当前目录 `.cc-agent-router.yaml`;
4. 当前目录 `cc-agent-router.yaml`;
5. `~/.config/cc-agent-router/config.yaml`。

显式指定的配置不存在时会直接报错,不会静默回退到其他文件。

### 完整结构

```yaml
version: 1

defaults:
  claudeExecutable: claude
  # Windows 只有 claude.cmd 时,可使用 node.exe + CLI JS:
  # claudeExecutable: C:/Program Files/nodejs/node.exe
  # claudeExecutableArgs: [C:/path/to/@anthropic-ai/claude-code/cli.js]

  cwd: .
  artifactsDir: E:/claude-agent-runs
  timeoutMs: 1800000
  permissionMode: dontAsk
  maxOutputChars: 8000000
  keepArtifacts: false

  # 默认只继承运行必需环境。工具链确实需要其他非敏感变量时显式加入:
  # inheritEnv: [HTTP_PROXY, HTTPS_PROXY]

providers:
  api-a:
    baseUrl: https://api-a.example.com
    authTokenEnv: API_A_KEY

  api-b:
    baseUrl: https://api-b.example.com
    apiKeyEnv: API_B_KEY

  # 也可将其他子进程变量映射到父进程环境变量:
  # bedrock-a:
  #   env:
  #     CLAUDE_CODE_USE_BEDROCK: "1"
  #     AWS_REGION: us-east-1
  #   envFrom:
  #     AWS_ACCESS_KEY_ID: BEDROCK_A_ACCESS_KEY_ID
  #     AWS_SECRET_ACCESS_KEY: BEDROCK_A_SECRET_ACCESS_KEY
  #     AWS_SESSION_TOKEN: BEDROCK_A_SESSION_TOKEN

agents:
  research:
    provider: api-a
    model: model-a
    effort: high
    description: 调研代码、文档和外部资料;只读
    permissionMode: plan
    tools: [Read, Glob, Grep, WebSearch, WebFetch]
    maxBudgetUsd: 3
    appendSystemPrompt: 只调研并给出有来源的结论,不修改文件。

  implement:
    provider: api-b
    model: model-b
    effort: high
    description: 按明确方案修改代码并测试
    permissionMode: acceptEdits
    tools: [Read, Glob, Grep, Edit, Write, Bash]
    maxBudgetUsd: 5
```

### Defaults 字段

| 字段 | 说明 |
|---|---|
| `claudeExecutable` | Claude Code 可执行程序,默认 `claude` |
| `claudeExecutableArgs` | 可执行程序前置参数;Windows 用 `node.exe` 启动 CLI JS 时有用 |
| `cwd` | 默认项目工作目录;相对路径按配置文件目录解析 |
| `artifactsDir` | 运行文件根目录;不存在时自动创建;相对路径按配置文件目录解析 |
| `timeoutMs` | headless 默认超时,1–2147483647 毫秒 |
| `permissionMode` | 默认 Claude Code 权限模式 |
| `maxOutputChars` | stdout + stderr 最大字符数,防止无限输出占用内存 |
| `keepArtifacts` | headless 完成后是否保留本次运行目录 |
| `inheritEnv` | 额外继承的非敏感环境变量名 |

### Provider 字段

| 字段 | 说明 |
|---|---|
| `baseUrl` | 映射为子进程 `ANTHROPIC_BASE_URL` |
| `apiKeyEnv` | 从父环境读取值,映射为 `ANTHROPIC_API_KEY` |
| `authTokenEnv` | 从父环境读取值,映射为 `ANTHROPIC_AUTH_TOKEN` |
| `env` | 非敏感的字面量环境变量 |
| `envFrom` | 子进程变量名到父进程变量名的映射 |
| `ccSwitch` | CC Switch 数据库路径和 provider ID 引用 |

`apiKeyEnv` 与 `authTokenEnv` 只能配置一个。不要把真实 key 写进 `env` 或 YAML。

设置凭据示例:

PowerShell:

```powershell
$env:API_A_KEY = "your-api-key"
$env:API_B_KEY = "your-api-key"
```

Bash:

```bash
export API_A_KEY='your-api-key'
export API_B_KEY='your-api-key'
```

应在**启动主 Claude Code 的同一环境**中设置变量,让 MCP server 可以读取它们。

### 启动参数如何对应

每次运行先选择一个 `agents` 角色,再由该角色组合 provider、模型、权限模式和思考强度。Terminal 模式生成的核心命令类似:

```text
claude --model opus --permission-mode plan --effort high --tools=Read,Glob,Grep -- "任务"
```

Windows 外层使用:

```text
wt.exe -w new powershell.exe -NoLogo -NoExit -File run-agent.ps1
```

Headless 模式不会打开窗口,并额外传入:

```text
--no-session-persistence --print --output-format json
```

配置与命令行的对应关系:

| 配置 | 作用 |
|---|---|
| `agent.provider` | 选择 provider,并向该子进程注入对应的 Base URL 和凭据 |
| `agent.model` | 生成 `--model`;CC Switch provider 应使用 `default/fable/opus/sonnet/haiku` 档位 |
| `agent.permissionMode` | 生成 `--permission-mode`;若希望首次进入 Plan 模式,配置为 `plan` |
| `agent.effort` | 生成 `--effort`,支持 `low/medium/high/xhigh/max` |
| `agent.tools` | 生成 `--tools=...` |
| CLI `--mode` | `headless` 自动返回结果;`terminal` 打开可见且可继续交互的新 Claude Code 窗口 |

权限模式可配置为 `plan`、`acceptEdits`、`manual`、`dontAsk`、`auto` 或 `bypassPermissions`。推荐只读角色使用 `plan`,实现角色使用 `acceptEdits`;不要默认使用 `bypassPermissions`。角色级 `permissionMode` 优先于 `defaults.permissionMode`。

例如,让新窗口第一次启动时处于 Plan 模式并使用高思考强度:

```yaml
agents:
  research:
    provider: api-a
    model: model-a
    permissionMode: plan
    effort: high
```

对于手动 provider,`apiKeyEnv`/`authTokenEnv` 填写的是**父进程环境变量名**,不是密钥本身。路由器读取该变量后,仅向目标 Claude 子进程设置 `ANTHROPIC_API_KEY` 或 `ANTHROPIC_AUTH_TOKEN`。对于 CC Switch provider,路由器在每次调用时只读数据库,取得目标 provider 的最新 Base URL、凭据和模型档位映射。

### Agent 字段

| 字段 | 说明 |
|---|---|
| `provider` | 必填,引用 `providers` 中的名称 |
| `model` | 必填,传给 Claude Code 的 model 字符串 |
| `fallbackModel` | headless fallback model,支持字符串或数组 |
| `effort` | `low / medium / high / xhigh / max` |
| `description` | 角色用途,供主 Claude 选择 |
| `systemPrompt` | 替换 system prompt |
| `appendSystemPrompt` | 追加 system prompt;不能与 `systemPrompt` 同时使用 |
| `tools` | 可用工具集合 |
| `allowedTools` | 允许工具规则 |
| `disallowedTools` | 禁止工具规则 |
| `permissionMode` | 角色权限模式 |
| `maxBudgetUsd` | headless 最大费用预算 |
| `timeoutMs` | 角色超时覆盖 |
| `settings` | 可选 Claude Code settings 覆盖;仅设置时才生成 `--settings` 文件 |

---

## 从 CC Switch 导入

如果已经用 CC Switch 管理 Claude provider,可以自动生成路由配置:

```bash
node dist/cli.js import-cc-switch -o cc-agent-router.yaml
```

指定数据库:

```bash
node dist/cli.js import-cc-switch \
  --database /path/to/.cc-switch/cc-switch.db \
  --output cc-agent-router.yaml
```

导入器会:

1. 以 SQLite read-only 模式读取 `providers`;
2. 只处理 `app_type = 'claude'`;
3. 为 provider 生成稳定名称;
4. 按 Claude 模型档位(`default` / `fable` / `opus` / `sonnet` / `haiku`)生成角色,而不是上游模型名;
5. 把数据库路径和 provider ID 写进 YAML;
6. 不把 API key/token 复制到 YAML。

生成结构示例:

```yaml
providers:
  cc-switch-example:
    ccSwitch:
      database: /home/user/.cc-switch/cc-switch.db
      providerId: provider-uuid
    baseUrl: https://api.example.com

agents:
  cc-switch-example-opus:
    provider: cc-switch-example
    model: opus
    effort: high
    description: 从 CC Switch provider “example” 自动导入;opus 档映射到 example-opus-model
    permissionMode: dontAsk
```

### CC Switch 模型档位语义(重要)

CC Switch 的模型映射按 Claude 档位工作:

| Claude 档位 | CC Switch 环境变量 | 含义 |
|---|---|---|
| `default` | `ANTHROPIC_MODEL` | 无法识别档位时的默认模型 |
| `fable` | `ANTHROPIC_DEFAULT_FABLE_MODEL` | fable 档映射目标 |
| `opus` | `ANTHROPIC_DEFAULT_OPUS_MODEL` | opus 档映射目标 |
| `sonnet` | `ANTHROPIC_DEFAULT_SONNET_MODEL` | sonnet 档映射目标 |
| `haiku` | `ANTHROPIC_DEFAULT_HAIKU_MODEL` | haiku 档映射目标 |

对 CC Switch provider,角色的 `model` 字段应写**档位**(`default` / `fable` / `opus` / `sonnet` / `haiku`),而不是上游模型名。运行时路由器会执行:

```text
claude --model opus
```

并把 CC Switch 的 `ANTHROPIC_DEFAULT_*_MODEL` 映射注入子进程,由 Claude Code 按档位选用对应的上游模型。**不要写 `model: gpt-5.6-sol` 这类上游模型名作为 `--model` 参数**——它绕过了档位映射,上游通常无法识别,会返回 503。

- `model: default` 时不传 `--model`,Claude Code 直接使用 `ANTHROPIC_MODEL`;
- 为兼容旧配置,如果 `model` 值恰好等于某个档位的映射目标(例如 `gpt-5.6-sol`),运行时会自动反解为对应档位(例如 `opus`);
- 非 CC Switch provider(手写 `apiKeyEnv`/`authTokenEnv`/`env`)不受影响,`model` 仍直接作为 `--model` 传递。

每次执行时会重新读取该 provider 的最新 `settings_config.env`。因此:

- 更新 key:不需要重新导入;
- 更新 base URL:运行时也会读取最新值;
- 更新某档位的上游模型:运行时也会读取最新映射;
- 新增/删除 provider 或 model 档位:需要重新导入以更新角色列表。

> 导入依赖系统 Python 的 `sqlite3` 标准库,不需要安装原生 Node SQLite 扩展。

---

## CLI 使用

### 查看帮助

```bash
ccar --help
ccar run --help
```

### 列出角色

```bash
ccar --config cc-agent-router.yaml list
```

### 后台执行

```bash
ccar --config cc-agent-router.yaml run \
  --role research \
  --cwd /path/to/project \
  --prompt "分析认证流程,列出关键文件、调用链和风险"
```

从 stdin 读取任务:

```bash
printf '%s' '审查当前实现,只报告可复现问题' | \
  ccar --config cc-agent-router.yaml run --role review
```

### 打开可见终端

```bash
ccar --config cc-agent-router.yaml run \
  --role implement \
  --mode terminal \
  --cwd /path/to/project \
  --artifacts-dir /path/to/agent-runs \
  --prompt "按项目计划实现功能并运行测试"
```

Windows PowerShell:

```powershell
ccar --config E:/configs/cc-agent-router.yaml run `
  --role implement `
  --mode terminal `
  --terminal auto `
  --cwd E:/projects/my-app `
  --artifacts-dir E:/claude-agent-runs `
  --prompt "实现当前任务"
```

`--terminal` 可选:

- `auto`:Windows Terminal → PowerShell 回退;
- `windows-terminal`:只使用 Windows Terminal;
- `powershell`:直接打开 PowerShell;
- `cmd`:通过 cmd 新窗口承载 PowerShell 启动脚本。

### Dry run

仅检查将使用的角色、provider、model 和参数,不读取真实凭据、不调用 API:

```bash
ccar --config cc-agent-router.yaml run \
  --role implement \
  --prompt "实现功能" \
  --dry-run
```

### 结构化输出

```bash
ccar --config cc-agent-router.yaml run \
  --role review \
  --prompt "审查当前改动" \
  --schema review.schema.json \
  --json
```

### 命令总览

| 命令 | 用途 |
|---|---|
| `list` | 列出角色,不显示凭据 |
| `run` | 运行 headless 或 terminal 子代理 |
| `mcp` | 启动 stdio MCP server |
| `import-cc-switch` | 只读导入 CC Switch provider/model |
| `install-claude` | 安装 Claude Code Plugin(MCP + Skill) |
| `uninstall-claude` | 卸载 Plugin |
| `init` | 生成示例配置 |

---

## 安装为 Claude Code Plugin

这是推荐方式。安装器会生成:

```text
~/.claude/skills/cc-agent-router/
├── .claude-plugin/
│   └── plugin.json
├── .mcp.json
└── SKILL.md
```

- `.mcp.json` 启动本项目的 stdio MCP server;
- `SKILL.md` 告诉主 Claude 在大型任务中如何选择和编排角色;
- API key 不会写入插件。

### 使用已有路由配置

```bash
npm run build
node dist/cli.js install-claude \
  --router-config /absolute/path/to/cc-agent-router.yaml
```

Windows:

```powershell
node dist/cli.js install-claude `
  --router-config E:/configs/cc-agent-router.yaml
```

### 自动从 CC Switch 导入并安装

```bash
node dist/cli.js install-claude
```

默认在当前目录生成 `cc-agent-router.yaml`,然后安装 Plugin。

指定数据库:

```bash
node dist/cli.js install-claude \
  --cc-switch-database /path/to/.cc-switch/cc-switch.db
```

安装后重启 Claude Code,或执行:

```text
/reload-plugins
```

然后可以对 Claude 说:

```text
使用 cc-agent-router,让不同角色完成这个任务:先调研和设计,再实现,最后独立审查和测试。
```

### 覆盖升级与卸载

如果 Plugin 的 `.mcp.json` 指向独立的长期安装目录(例如 Windows 上的 `C:/Users/you/cc-agent-router`),应直接在**该目录**拉取更新、构建并重装。不要只更新另一个开发副本,否则当前 Claude Code 仍会运行旧代码。

升级前先确认本地修改和实际配置已备份:

```bash
git status
git diff
git pull --ff-only
npm install
npm run build
node dist/cli.js install-claude \
  --router-config /absolute/path/to/cc-agent-router.yaml \
  --force
```

安装后必须重启 Claude Code,或执行:

```text
/reload-plugins
```

MCP server 是常驻进程;仅替换 `src/` 或 `dist/` 文件不会让已启动的会话自动加载新版本。

卸载:

```bash
node dist/cli.js uninstall-claude
```

> `.mcp.json` 指向安装时本项目的绝对 `dist/cli.js` 路径。安装后不要移动或删除项目目录,否则需重新安装 Plugin。建议只保留一个长期运行副本,避免“开发目录已更新、Plugin 仍指向旧目录”的版本漂移。

---

## 仅配置 MCP

如果不想安装自动编排 Skill,只注册 MCP:

```bash
claude mcp add --scope user cc-agent-router -- \
  node /absolute/path/to/cc-agent-router/dist/cli.js \
  --config /absolute/path/to/cc-agent-router.yaml \
  mcp
```

主 Claude 会获得两个工具:

- `delegate`:选择角色并启动子代理;
- `list_agents`:查看角色、provider、model、effort 和描述,不返回凭据。

`delegate` 的主要参数:

```json
{
  "role": "implement",
  "prompt": "完整、自包含的任务说明",
  "cwd": "/path/to/project",
  "artifactsDir": "/path/to/agent-runs",
  "timeoutMs": 1800000,
  "mode": "headless",
  "terminal": "auto"
}
```

如果仅注册 MCP,建议在项目 `CLAUDE.md` 添加:

```markdown
## 多模型委派

处理大型任务时:
1. 调研使用 cc-agent-router 的 research 角色。
2. 架构和计划使用 design。
3. 边界明确后使用 implement。
4. 实现后分别使用 review 和 test,二者不得修改代码。
5. 主代理整合结果、解决冲突并最终验证。
6. 委派 prompt 必须包含 cwd、目标、边界、已有结论和验收标准。
```

---

## headless 与 terminal

| 特性 | `headless` | `terminal` |
|---|---|---|
| 执行方式 | 后台子进程 | 新图形终端窗口 |
| 返回最终文本给调用方 | 是 | 否 |
| 适合主 Claude 自动编排 | 是 | 否,主要用于人工监督 |
| 用户可继续交互 | 否 | 是 |
| 超时控制 | 是 | 启动后交由用户控制 |
| 自动清理运行目录 | 默认是 | 否,关闭窗口后手动清理 |
| Prompt 传递 | stdin | `--` 后的位置参数 |

推荐:

- 自动执行 `research → design → implement → review/test`:用 `headless`;
- 想实时查看或中途干预:用 `terminal`。

### 运行文件目录

通过以下任一方式指定:

```yaml
defaults:
  artifactsDir: /path/to/agent-runs
```

```bash
ccar run --artifacts-dir /path/to/agent-runs ...
```

```json
{ "artifactsDir": "/path/to/agent-runs" }
```

优先级:

```text
本次调用参数 > defaults.artifactsDir > 系统临时目录
```

根目录不存在时自动创建。每次调用创建:

```text
cc-agent-router-<UUID>/
```

terminal 脚本不会包含 provider 凭据;凭据只通过新终端进程环境传递。

---

## 配置继承与隔离边界

### 会继承的内容

子代理不会使用 `--bare`,也不会设置新的 `CLAUDE_CONFIG_DIR`,因此可加载:

- 用户 Claude Code settings;
- MCP servers;
- Skills;
- Plugins;
- hooks;
- memory;
- 当前项目的 `CLAUDE.md`;
- Claude Code 正常发现的其他项目配置。

### 不会继承的内容

每次调用仍是新的、无持久化 Claude Code 进程,不会自动知道:

- 主会话当前对话;
- 尚未写入文件的设计决定;
- 上一个子代理只在回复中给出的结论;
- 主会话临时获得但未保存的资料。

所以委派 prompt 应自包含,例如:

```text
在 /path/to/project 中实现登录限流。

背景:
- Express + PostgreSQL。
- 已决定每个 IP 每分钟 10 次。
- 不修改数据库结构。

要求:
1. 修改 src/auth/login.ts。
2. 添加单元测试。
3. 运行 npm test。

限制:
- 不修改 generated/。
- 保持 API 响应兼容。
- 不提交 Git commit。

返回:修改文件、设计说明、测试结果和遗留问题。
```

### 角色 settings

默认完全使用用户配置。只有角色显式声明 `settings` 时,才创建本次覆盖文件:

```yaml
agents:
  review:
    provider: api-c
    model: model-c
    settings:
      permissions:
        deny: [Edit, Write]
```

该文件通过 Claude Code 的 `--settings` 参数加载,不会创建空白用户配置目录。

---

## 权限与安全

### 推荐角色权限

```yaml
agents:
  research:
    permissionMode: plan
    tools: [Read, Glob, Grep, WebSearch, WebFetch]

  design:
    permissionMode: plan
    tools: [Read, Glob, Grep]

  implement:
    permissionMode: acceptEdits
    tools: [Read, Glob, Grep, Edit, Write, Bash]

  review:
    permissionMode: plan
    tools: [Read, Glob, Grep, Bash]
    disallowedTools: [Edit, Write]

  test:
    permissionMode: dontAsk
    tools: [Read, Glob, Grep, Bash]
    disallowedTools: [Edit, Write]
```

不要默认给所有角色使用 `bypassPermissions`。

### 凭据处理

- YAML 只记录凭据来源环境变量名,不记录值;
- CC Switch 导入只记录数据库路径和 provider ID;
- API key 不进入命令行;
- headless prompt 通过 stdin 传递;
- terminal 启动脚本不写入凭据;
- 已知凭据若出现在子进程输出中,会替换为 `[REDACTED]`;
- 父环境采用 allowlist 继承;
- 所有 provider 声明的凭据来源变量都从普通继承列表中排除。

### 这不是 OS sandbox

配置和进程隔离不能限制当前系统用户本身的文件权限。允许 `Bash/Edit/Write` 的子代理仍可能读写该账户可访问的文件、运行项目脚本和访问网络。

处理不可信仓库或程序时,请额外使用:

- Docker;
- Windows Sandbox;
- 虚拟机;
- 受限系统账户;
- 只读文件挂载。

### Plugin 继承带来的信任边界

继承现有 Plugin、MCP 和 hooks 是本项目有意提供的效率特性,也意味着子代理会执行这些组件。只安装和启用你信任的扩展,并了解它们可能访问的数据和网络。

---

## Node API

```ts
import { delegate, loadConfig } from "cc-agent-router";

const { config } = await loadConfig("cc-agent-router.yaml");

const result = await delegate(config, {
  role: "review",
  cwd: process.cwd(),
  artifactsDir: "./agent-runs",
  prompt: "审查当前实现,只报告可复现问题",
  mode: "headless",
});

if (!result.ok) {
  throw new Error(result.stderr || result.text);
}

console.log(result.text);
```

主要导出:

```ts
export { delegate } from "./runner.js";
export { findConfig, loadConfig } from "./config.js";
export { installClaudePlugin, uninstallClaudePlugin } from "./install.js";
export { importCcSwitch } from "./cc-switch.js";
export { RouterError } from "./errors.js";
```

---

## 故障排查

### `找不到配置文件`

显式传入绝对路径:

```bash
ccar --config /absolute/path/to/cc-agent-router.yaml list
```

或设置:

```bash
export CC_AGENT_ROUTER_CONFIG=/absolute/path/to/cc-agent-router.yaml
```

### `CREDENTIAL_MISSING`

确保凭据环境变量存在于**启动主 Claude / MCP server 的进程环境**:

```powershell
$env:API_A_KEY = "..."
claude
```

修改已经运行中的父终端之外的系统环境变量,通常不会自动注入现有 MCP server;请重启 Claude Code。

### Windows 无法运行 `claude`

Node 的 `spawn(..., shell: false)` 不一定直接启动 `.cmd`。建议:

```yaml
defaults:
  claudeExecutable: C:/Program Files/nodejs/node.exe
  claudeExecutableArgs:
    - C:/Users/you/AppData/Roaming/npm/node_modules/@anthropic-ai/claude-code/cli.js
```

请按本机实际安装路径调整。

### terminal 打不开

尝试明确指定:

```bash
ccar run --mode terminal --terminal powershell ...
```

Linux 需要可用的图形终端之一:

- `x-terminal-emulator`;
- `gnome-terminal`;
- `konsole`。

### Provider 在 CC Switch 能看到但调用失败(503)

最常见的原因是**模型映射方式不对**。CC Switch 的模型映射按 Claude 档位工作:

```text
--model opus   → ANTHROPIC_DEFAULT_OPUS_MODEL
--model sonnet → ANTHROPIC_DEFAULT_SONNET_MODEL
```

如果角色的 `model` 写成了上游模型名(例如 `gpt-5.6-sol`),Claude Code 会把它当成档位名去匹配映射,匹配不到就回退到 `ANTHROPIC_MODEL`,上游往往因此返回 503。

正确做法是对 CC Switch provider 使用档位:

```yaml
agents:
  research:
    provider: cc-switch-example
    model: opus          # 不是 gpt-5.6-sol
```

重新导入即可自动按档位生成:

```bash
node dist/cli.js import-cc-switch --output cc-agent-router.yaml --force
```

如果 provider 只支持 OpenAI 的 `/v1/chat/completions` 而不兼容 Anthropic `/v1/messages`,路由器无法自动转换协议,需要在中间部署协议转换代理。

### terminal 窗口报 `0x80070002` 或 `系统找不到指定的文件`

早期版本错误使用了 `wt.exe new-window ...`,Windows Terminal 不识别 `new-window` 子命令。当前版本已修复为:

```text
wt.exe -w new powershell.exe -NoLogo -NoExit -File run-agent.ps1
```

确认 Plugin 已更新并执行 `/reload-plugins`。仍失败时可显式指定:

```bash
ccar run --mode terminal --terminal powershell ...
```

### terminal 报 PowerShell `ParserError`(中文乱码)

早期版本生成的 `run-agent.ps1` 是无 BOM 的 UTF-8,Windows PowerShell 5.1 会按本地 ANSI/GBK 读取,中文 system prompt 因此变成乱码并破坏引号。当前版本写入时添加了 UTF-8 BOM(`EF BB BF`),PowerShell 5.1 可正确解析中文。

### terminal 报 `--no-session-persistence can only be used with --print mode`

`--no-session-persistence` 仅 headless 支持。当前版本已将该参数限定为 headless 模式,terminal 不再携带它。确认 Plugin 已更新并执行 `/reload-plugins`。

### 子代理看不到主会话刚才的结论

这是正常行为。它继承工具配置和项目文件,不继承主会话聊天记录。让主 Claude 将即时背景写进 `delegate.prompt`。

### terminal 目录越来越多

terminal 进程启动后脱离路由器,路由器无法可靠判断用户何时结束交互。关闭对应窗口后,手动删除 `cc-agent-router-<UUID>` 子目录。

### MCP 或 Skill 修改后未生效

重启 Claude Code,或执行:

```text
/reload-plugins
```

---

## 开发与测试

```bash
npm install
npm run check
npm test
npm run build
```

当前测试覆盖:

- Claude CLI 参数构造、prompt 脱敏和 terminal/headless 参数分离;
- CC Switch 档位模型语义(`opus` 等档位、上游模型名反解、`default` 不传 `--model`);
- 配置查找、schema 校验和相对路径解析;
- 子进程环境 allowlist 和凭据替换;
- dry-run;
- 自定义运行目录创建;
- terminal 脚本不落盘凭据;
- Windows Terminal `wt.exe -w new` 启动语法与 PowerShell/cmd 路径;
- Windows PowerShell 5.1 中文脚本 UTF-8 BOM 解析;
- MCP 真实握手和工具调用;
- Plugin 文件生成及 Claude 官方严格校验;
- CC Switch 只读导入、按档位生成角色且不复制凭据。

打包预览:

```bash
npm pack --dry-run
```

项目使用 TypeScript ESM,编译产物位于 `dist/`,不提交到 Git。

### 贡献

欢迎提交 Issue 和 Pull Request。提交前请确保:

```bash
npm run check
npm test
npm run build
```

不要在 issue、测试 fixture、日志或提交中包含真实 API key、token、CC Switch 数据库或本机私有配置。

---

## 设计来源

### CC Switch

- 仓库:<https://github.com/farion1231/cc-switch>(MIT)
- `src-tauri/src/provider.rs`:provider 保存 `settings_config`;
- `src-tauri/src/services/provider/live.rs`:Claude provider live switch;
- `src-tauri/src/config.rs`:Claude 配置路径解析。

本项目借鉴 provider/settings 数据模型,但不采用并发进程共享 live 配置的方式。

### OpenCode

- 仓库:<https://github.com/anomalyco/opencode>(MIT)
- `packages/core/src/v1/config/provider.ts`:provider 管理 key、base URL、models 和 options;
- `packages/core/src/v1/config/agent.ts`:agent 独立选择 model、prompt 和 permission;
- `packages/opencode/src/agent/agent.ts`:运行时解析 provider/model;
- `packages/opencode/src/config/config.ts`:进程级配置注入。

---

## 当前限制

- backend 是 Claude Code CLI,不直接运行 OpenCode、Codex 或 Gemini CLI;
- provider 必须兼容 Claude Code 使用的 Anthropic Messages API;
- 这是静态角色路由器,主 Claude/MCP 调用方负责选择角色;
- 子代理继承 Claude Code 配置,但不继承主会话对话;
- terminal 最终回复不会自动回填主会话;
- terminal 运行目录需要用户在关闭窗口后清理;
- 配置和进程隔离不是 OS sandbox;
- CC Switch 导入依赖本机 Python `sqlite3`;
- Plugin MCP 配置指向安装时的项目绝对路径,移动项目后需重装。

---

## 开源协议

本项目使用 [MIT License](LICENSE)。

本项目与 Anthropic、Claude Code、CC Switch 和 OpenCode 的原作者/维护者无隶属关系。Claude 和 Claude Code 是 Anthropic 的相关商标或产品名称。