内容
<div align="center">
# cc-delegate
**将整个开发任务从前沿模型监督者委派给更便宜的 worker 模型 —**
**隔离在 git 工作树中,根据评分标准进行评估,作为一个干净的差异进行审查。**
[](LICENSE)
[](https://docs.claude.com/en/docs/claude-code/overview)
[](https://docs.astral.sh/uv/)
<img src="docs/demo.gif" alt="cc-delegate demo: the supervisor plans the work, hands it to a worker model, then reviews the finished branch" width="720">
</div>
你的监督者 — Claude Code 在前沿模型上 — 停留在 Anthropic 并继续做它擅长的事情:规划和审查。一个 worker 在任何更便宜的 litellm-routable 模型上进行后台实现,在其自己的 git 工作树中。你审查一个差异在结束时,而不是观看一个不完整的编辑流,并且只有 worker 的 tokens 才会落在替代提供商上。
## 为什么选择 cc-delegate
- **整个任务,而不是按调用路由。** 一个 `run_dev_task` 将一个完整的有界任务 — 实现、测试、迭代 — 移交给一个更便宜的模型,单次调用即可完成,而不是路由单个补全。
- **隔离的构造方式。** 每个任务都在其自己的 `delegate/<task_id>` 分支上的一个单独的 git 工作树中运行。直到你审查差异之前,不会触及你的工作树。
- **“完成”是有评判标准的,而不是声称的。** 一个评分标准根据你的 `definition_of_done` 和 `test_command` 检查结果,因此 worker 不能仅凭自己的说法声明胜利。
- **非阻塞的。** `run_dev_task` 立即返回一个 `task_id`,而 worker 在后台运行。监督者结束其回合并按照其设定的时间表轮询,因此在中间你拥有其全部注意力。
- **有界限的。** 成本上限、git 历史保护和停滞监视器可以防止失控的 worker 超出其限制,触及共享分支或挂起超过其限制。
## 委托的样子
要求监督者承担一些大型任务,封装的技能就会启动:
> **你:** 委托在 `src/auth/` 中实现 token-refresh 流 — 测试必须通过。
>
> **监督者:** 启动委托任务… `run_dev_task` → `t_…yqsldx`. 我过几分钟后会回来查看。
>
> *(几次廉价的状态轮询后)*
>
> **监督者:** 完成 — 4 个文件已更改,测试通过,$0.24. 这是差异。
worker 以 $0.24 的价格完成了这项任务;监督者只花费了几个 token 来确定任务范围和读取差异。这就是重点 — 昂贵的模型进行规划和审查,便宜的模型进行输入。
**何时委托。** 在大型有界工作中使用它:多文件功能、重构、测试和迭代循环。对于一行修复和只读问题,请跳过它 — 监督者直接更快地回答这些问题。
## 与其他工具的比较
这些工具与 cc-delegate 重叠,但不是直接替代品;每个工具都位于设计空间的不同点上。我尚未在实际战斗中运行它们,因此以下注释仅基于文档 — 方向性的,而不是基准测试。
| 维度 | cc-delegate | [houtini-lm](https://github.com/houtini-ai/houtini-lm) | [Roo Code](https://docs.roocode.com/features/boomerang-tasks) Orchestrator |
|---|---|---|---|
| 工作单元 | 一个具有自己的代理循环的整个多回合任务 | 单个模型调用,按请求路由 | Roo 的编排器/模式系统中的子任务 |
| 补全检查 | 根据你的 `definition_of_done` / `test_command` 进行评分 | 调用者决定 | 编排器读取子任务的摘要 |
| 隔离 | 自己的 git 工作树 + 每个任务的分支 | 按调用,因此没有持久状态隔离 | 每个子任务的独立上下文,共享工作空间 |
| 运行期间 | 异步:返回 `task_id`,监督者按自己的时间表轮询 | 同步:调用者等待调用 | 同步:编排器等待子任务 |
| 设置和开销 | 需要 `uv` 和每个任务的工作树 | 只是一个 MCP 调用 — 无需配置 | 安装 VS Code 扩展 |
**实际上。** houtini-lm — 也是一个 Claude Code MCP 服务器 — 是一个更轻量级的选择,当你想要路由单个补全并且不需要隔离或任务循环时;无需配置。Roo Code 适合在具有自己的 UI 的完整 VS Code 扩展中工作,而不是 Claude Code 插件。两者都支持许多提供商 — houtini-lm 通过本地运行时(LM Studio、Ollama、vLLM)和托管的提供商,Roo Code 通过 LiteLLM 支持每个模式 — 因此提供商的广度不是决定轴。cc-delegate 在你要委派的是一个完整的有界任务并获得一个审查的差异时,才值得其工作树和评分标准的开销。
## 安装
安装插件是一条命令,但有两个独立于 Claude Code 控制的东西:一个 worker API 密钥和 `uv`。两者都不能保证你有 Claude Code。按顺序进行:
**1. 获取 worker API 密钥。** 你需要一个密钥用于 worker 运行的提供商。出于默认情况下,这是 MiniMax — 在 [platform.minimax.io](https://platform.minimax.io) 注册并生成一个密钥 — 但任何 litellm-routable 提供商都可以使用;跳转到 [配置](#配置) 以设置其他提供商。
**2. 安装 [uv](https://docs.astral.sh/uv/getting-started/installation/)**,如果 `uv --version` 没有显示它。 这是唯一的运行时先决条件:`uv run` 在第一次使用时解析服务器和 worker 的内联 Python 依赖项(以及 Python 本身,如果需要) — 无需 `pip install`,无需 Node.js,无需构建步骤。
**3. 将 `DELEGATE_API_KEY` 设置为持久环境变量,然后重启 Claude Code.** 这是可能导致问题的一步:`.mcp.json` 的 `${DELEGATE_API_KEY}` 只读取启动 Claude Code 的 OS 级环境 — 没有 `.env` 自动加载,也没有交互式提示。设置它 *之后* Claude Code 已经运行是无效的,直到你从具有该变量的 shell 重启。
```powershell
# Windows (PowerShell) — 在终端之间持续;之后重启 Claude Code
[Environment]::SetEnvironmentVariable("DELEGATE_API_KEY", "your-key-here", "User")
```
```bash
# macOS/Linux — 添加到 ~/.zshrc 或 ~/.bashrc,然后打开新的 shell
export DELEGATE_API_KEY="your-key-here"
```
**4. 安装插件。**
```
/plugin marketplace add EtienneLescot/cc-delegate
/plugin install cc-delegate@cc-delegate-marketplace
```
或在开发过程中本地安装:`claude --plugin-dir .`
**5. 验证。** 运行 `/mcp` — 检查点显示缺少的 `uv` 密钥,以免任务进行中。
## 配置
**外观(首选)。** 插件通过其自己的 MCP 工具进行配置,通过 Claude Code 对话式驱动 — 无需重启,变更立即生效:
- *"显示提供商状态"* → `provider_status` 列出您的模型配置文件、默认配置文件和每个配置文件的身份验证状态(密钥可达?OAuth 令牌缓存存在?)。
- *"添加 deepseek 配置文件"* → `set_model_profile("deepseek", "litellm:deepseek/deepseek-chat", "DEEPSEEK_API_KEY")`;`set_default_profile` / `remove_model_profile` 管理菜单。
- *"添加 deepseek 失败时的备用方案"* → `set_model_profile("mm", "litellm:minimax/MiniMax-M3", "MINIMAX_API_KEY", fallback_models=["litellm:deepseek/deepseek-chat"])` — 按顺序尝试,如果主要模型的调用失败,则使用 litellm 自己的备用机制。
- *"存储 deepseek 配置文件的密钥"* → `store_api_key("deepseek")` 通过 native Claude Code 对话框(MCP 诱导,Claude Code ≥ 2.1.199)询问密钥:密钥直接发送回服务器,不会进入模型的对话中。
- 按任务:*"在此配置文件上委托"* → `run_dev_task(..., profile="deepseek")`。监督者的技能禁止它在不选择默认配置文件的情况下自行选择配置文件。
配置文件存储在 `~/.cc-delegate/config.json` 中,存储的密钥存储在 `~/.cc-delegate/credentials.json` 中。任何 litellm-routable 模型都可以使用 — 请参阅 [litellm 的提供商列表](https://docs.litellm.ai/docs/providers)。
**订阅提供商(OAuth)。** 对于 OAuth 提供商的配置文件 — GitHub Copilot(`set_model_profile("copilot", "litellm:github_copilot/gpt-5")`,无 API 密钥)或 ChatGPT(`set_model_profile("chatgpt", "litellm:chatgpt/gpt-5.3-codex")`) — 运行 `setup_provider_auth("<profile>")`。它返回一个验证 URL 和用户代码;访问 URL,输入代码,授权,然后 `auth_poll(flow_id)` 转换为 `authorized`。litellm 缓存令牌,因此后续运行无需交互,密钥从不触及配置。设备流用于 GitHub Copilot;ChatGPT 适配器也以相同方式连接,但尚未运行到端到端的实时订阅。
> **服务条款。** (这因提供商而异):OpenAI 支持第三方工具使用 ChatGPT 订阅 — 其 *Codex for Open Source* 程序明确列出了此类工具 — 而 GitHub Copilot 的设备流被第三方编辑器广泛使用。Anthropic 禁止在 Claude Code 自身范围之外使用订阅,Google 对 Gemini CLI 也是如此,因此 cc-delegate 不为两者实现 OAuth。
**旧环境路径(仍受支持)。** 见 [.env.example](.env.example) 完整列表:`DELEGATE_API_KEY`、`DELEGATE_MODEL`、`DELEGATE_API_KEY_ENV_VAR` 和防护措施(`DELEGATE_RECURSION_LIMIT`、`DELEGATE_RUBRIC_MAX_ITERATIONS`、`DELEGATE_TIMEOUT_MS`、`DELEGATE_STALL_TIMEOUT_S`、`DELEGATE_MAX_BUDGET_USD`、`DELEGATE_ASK_TIMEOUT_S`)。当未定义配置文件时,此路径适用;环境变更需要重启 Claude Code(安装步骤 3 中的重启陷阱仅与此路径相关)。
## 架构
```mermaid
flowchart LR
Supervisor["Claude Code 监督者<br/>(Anthropic API)"]
MCP["cc-delegate MCP 服务器<br/>Python (uv 运行 server/main.py)、stdio<br/>run_dev_task(异步)、get_task_status、<br/>get_task_progress、answer_worker、steer_task、<br/>cancel_task、fetch_task_result、cleanup_task"]
Worktree["可丢弃的 git 工作树<br/>分支 delegate/<task_id>"]
Worker["uv 运行 worker/worker.py<br/>deepagents 循环<br/>+ 实现者 / 测试者 / 审查者子代理<br/>+ 评分标准"]
Provider["提供商<br/>(litellm 路由,<br/>例如 MiniMax M3)"]
Review["监督者审查<br/>补丁 / 差异"]
Supervisor -->|"run_dev_task /<br/>get_task_status / get_task_progress /<br/>steer_task / fetch_task_result / cleanup_task"| MCP
MCP -->|"createWorktree()"| Worktree
MCP -->|"uv 运行 worker.py"| Worker
Worker -->|"litellm 补全"| Provider
Provider -->|"模型响应"| Worker
Worker -->|"PROGRESS: {step, node, ...}<br/>QUESTION: {id, message}<br/>(实时,每步刷新)<br/>RESULT_JSON: {status, summary,<br/>turns, cost_usd, total_tokens,<br/>rubric_status, error}"| MCP
MCP -->|"状态 + 进度<br/>(get_task_status, 轮询)"| Supervisor
Worktree -->|"git diff --cached"| MCP
MCP -->|"补丁 + 差异"| Review
```
**MCP 服务器**(`server/main.py`,官方 `mcp` Python SDK,通过 `uv 运行`)向监督者公开委托工具,通过 stdio:
| 工具 | 它做什么 |
|---|---|
| `run_dev_task` | 启动委托任务(预先检查 `test_command`)并立即返回 `task_id` — worker 在后台运行。 |
| `get_task_status` | 廉价的活跃度:`running` / `needs_input` / `done`。按需轮询。 |
| `get_task_progress` | 详细审计:已写入的文件、最近的活动、成本。偶尔调用。 |
| `answer_worker` | 回复阻塞在问题上的 worker。 |
| `steer_task` | 重定向正在运行的 worker — 在其下一个工具调用时交付。 |
| `cancel_task` | 杀死卡住/失控的 worker 的整个进程树,保留其工作。 |
| `fetch_task_result` | 最终总结、补丁、更改的文件、成本 — 包括从失败运行中挽救的工作。 |
| `cleanup_task` | 拆除已完成的任务的工作树、分支和持久的作业文件。 |
- **作业持久性 — 每个作业在状态更改时都会镜像到 `<repo>/.cc-delegate/jobs/<task_id>.json`,因此状态、结果和清理查询在 MCP 服务器重启后存活:内存中的注册表按需从磁盘重建。- **worker**(`worker/worker.py`)是一个 [deepagents](https://github.com/langchain-ai/deepagents) 代理,作为子进程通过 `uv 运行`。它使用 `LocalShellBackend` 在 `virtual_mode=True` 下限制文件系统和 shell 访问到工作树,使用 `SubAgent`s 实现者/测试者/审查者角色和使用 `RubricMiddleware` 根据您的 `definition_of_done`/`test_command` 等级完成度,而不是模型自己的“我完成了”。每个运行通过 litellm 回报 `cost_usd` 和 `total_tokens` 并打印每步的 `PROGRESS:` 行。
- **打包的技能**(`skills/delegate-heavy-dev/SKILL.md`)教会监督者何时如何委托。
<details>
<summary><b>为什么使用 deepagents-as-a-library 而不是 CLI 代理</b></summary>
我们从 worker 调用 `@anthropic-ai/claude-agent-sdk` 的 `query()` 指向第三方端点,然后尝试 shell 外壳到 CLI 编码代理(OpenCode,`dcode`) — 两者都遇到未解决的 Claude Code CLI 无头身份验证错误或 `dcode` 的 Windows/无 TTY 挂起。直接调用 `deepagents` 作为库规避两者:无 CLI,无 TTY 依赖项,并且对循环(子代理,基于评分标准的收敛)具有实际控制权而不是黑盒 CLI。
完整的故事 — 三个工作引擎,两个上游错误 — 在 [docs/build-journey.md](docs/build-journey.md);可复制的错误报告在 [KNOWN_ISSUES.md](KNOWN_ISSUES.md)。
</details>
## 监督模型 - 异步,定时轮询
`run_dev_task` 立即返回一个 `task_id`,而 worker 在后台运行。监督者永远不会阻塞:标准的 MCP 服务器无法进入模型的上下文,因此 worker 无法调用监督者 — 但监督者不需要坐着等待。标准轮询工具按成本分开,因此频繁检查保持廉价:
- **`get_task_status`** — 一个小载荷(`running` / `needs_input` / `done`,以及如果被阻塞则待处理的问题)。自由轮询;它几乎触及上下文。
- **`get_task_progress`** — 详细审计(写入的文件、最近的 shell 命令、步骤、成本、经过的时间)。较重,因此监督者偶尔调用它,或当您询问“进展如何?”时。
在 `needs_input` 上,监督者决定:从自己的上下文使用 `answer_worker`,或将问题转发给您,当它真正是您的调用时。在 `done` 上,它使用 `fetch_task_result` 进行审查。
对于 **大工作**,监督者将大任务分解为有界的子任务并运行独立的(不同的文件)**并行** — 每个 `run_dev_task` 获取自己的工作树/分支 — 而对触摸相同文件的子任务进行序列化以避免合并冲突。
<details>
<summary><b>为什么不阻塞的“watch”调用或 MCP 进度通知?</summary>
两者都被尝试并移除。阻塞调用冻结监督者的整个运行,而进度通知从不进入模型的上下文并且不会被评估器发送到您时,它会审查。
</details>
## 状态栏 - 始终可见的环境指示器(TUI)
对于一个被动、扫视可见的视图,无需询问监督者,该状态栏在Claude Code 的状态栏中保持一行总结,免费(仅 TUI - 桌面应用不会渲染自定义状态栏):
```
⏳ delegate t_…yqsldx · MiniMax-M3 · step 24 · writing src/auth/tokens.js
⚠ delegate t_…yqsldx · asks: which token TTL? · → answer_worker
✓ delegate t_…yqsldx · done · 4 files · $0.24
```
它在两端保持免费:MCP 服务器(已经驻留)渲染行在Python中并写入 `~/.cc-delegate/statusline`;Claude Code 运行的状态行脚本是一个依赖项免费的读取器(无 `jq`,无 `python`,无 JSON解析),只要它新鲜就打印预制行。
在 `~/.claude/settings.json` 中一次连接(`refreshInterval` 是必需的 - 在会话等待后台工作时,状态行事件触发器会变静默):
```json
{
"statusLine": {
"type": "command",
"command": "~/.claude/cc-delegate-statusline.sh",
"refreshInterval": 2
}
}
```
复制 `statusline/cc-delegate-statusline.sh`(或在没有 Git Bash 的 Windows 上,无 `.ps1` 变体)到 `~/.claude/` 并 `chmod +x`。正在运行的任务每事件刷新一行;阻塞任务保持其问题可见,直到您回答;完成任务显示一个简短的总结,然后渐隐 - 屏幕上不会留下任何过期状态。
在 `~/.claude/` 中连接一次并 `chmod +x`。正在运行的任务每事件刷新一行;阻塞任务保持其问题可见,直到您回答;完成任务显示一个简短的总结,然后渐隐 - 屏幕上不会留下任何过期状态。
## 工作节点与监管者之间的通信(和控制)
工作节点并非一次性运行。三个工具被注入到其代理循环中:
- **`report_progress(update)`** — 在阶段转换时触发的即时执行语句;它们通过 `get_task_progress` 和状态行显示。
- **`ask_supervisor(question, context)`** — 阻塞工作节点(等待时零令牌)并将任务转换为 `needs_input`。监管者在下一次 `get_task_status` 轮询时发现问题,从其自己的上下文中回答或将其转发给您,然后使用 `answer_worker` 回复。如果在 `DELEGATE_ASK_TIMEOUT_S` (默认 600 秒)内没有收到答案,工作节点会根据其最佳保守判断继续执行。
- **`report_blocker(problem, attempts)`** — 同样的机制,用于 "我已经在同一个错误上失败了 3 次":监管者可以纠正方向,而不是让工作节点在超时之前一直尝试。
答案通过 `<repo>/.cc-delegate/comm/<task_id>/` 中的文件邮箱进行传递,而不是通过模型对话。
**另一个方向 — `steer_task(task_id, message)`** 允许监管者在任何时候重定向正在运行的工作节点,而不仅仅是对问题的回复: *"停止实现 X,改为执行 Y。"* 它不会阻塞工作节点或更改其状态;消息会放在邮箱中,直到工作节点的下一次工具调用,通常在几秒内。(在任务中途中断 LangGraph 步骤需要检查点,而此架构不使用检查点。)在测试中,在任务中途发送的消息会在下一个 shell 命令的输出中显示,工作节点在其后续回合中更改了方向。
## 安全
- **工作目录隔离。** 工作节点的 `LocalShellBackend` 在 `virtual_mode=True` 下运行,将文件系统和 shell 访问范围限定在可丢弃的工作目录中。监管者始终在合并 `delegate/<task_id>` 分支之前审查差异。
- **Git 历史保护。** `SupervisedShellBackend` 在运行前拒绝 `git push` / `merge` / `rebase` — 工作节点仅在其自己的可丢弃分支上运行,因此没有合法的理由触及共享历史。
- **预算上限。** `run_dev_task(..., max_budget_usd=...)` (默认为 `DELEGATE_MAX_BUDGET_USD`,5 美元)会在累积成本超过上限时停止工作节点,在每一步后检查实时成本跟踪器 — 因此运行不会无限期漂移。
- **停滞监视器。** 如果工作节点在 `DELEGATE_STALL_TIMEOUT_S` (默认 300 秒)内保持沉默 — 例如,在 rubric 分级内部调用挂起 — 其进程树将被终止,运行将快速失败,而不是挂起直到整个 30 分钟运行超时。 补救仍然运行,因此已完成的工作不会丢失。合法等待 `answer_worker` 的工作节点除外。
- **机密过滤。** 工作节点的 shell 环境会删除任何匹配 `API_KEY`/`TOKEN`/`SECRET`/`PASSWORD`/`CREDENTIAL` 的内容;存储在 facade 中的密钥和 OAuth 令牌永远不会进入模型的对话。
## 维护者
无构建步骤。服务器是纯 Python(`server/`,标准库 + `mcp` SDK 在 `main.py` 中内联声明);工作节点是 `worker/worker.py`。使用以下命令运行测试套件:
```bash
uv run python -m unittest discover -s server -p "test_*.py"
```
验证端到端连接:
- `/mcp` 列出了 `cc-delegate` 服务器及其工具。
- 监管者会话中的 `/status` 仍然显示 `api.anthropic.com` — 永远不会有工作节点配置泄漏到监管者进程中。
- 请求监管者委托一个繁重的任务;它应该调用 `run_dev_task`,轮询 `get_task_status`,然后通过 `fetch_task_result` 显示差异。
## 许可证
该存储库的自身代码使用 MIT 许可证。有关第三方使用条款的说明,请参见 [`NOTICE`](NOTICE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器