s18: Worktree Isolation — 各干各的,互不干扰
s01 → ... → s16 → s17 → s18 → s19 → s20
"各干各的目录, 互不干扰" — 任务管目标, worktree 管目录, 按 ID 绑定。
Harness 层: 隔离 — 并行执行的目录隔离。
问题
s17 中,Alice 和 Bob 都在同一个目录下工作。Alice 的任务是"重构认证模块",Bob 的任务是"重构 UI 登录页"。
Alice write_file("config.py", ...)。Bob 也 write_file("config.py", ...)。两个人改同一个文件,互相覆盖。而且无法干净地回滚——分不清哪些改动是谁的。
s15-s17 解决了"谁干什么"(任务系统)和"怎么通信"(消息总线),但没解决"在哪干"。
解决方案
)
Git worktree 让你在同一仓库中创建多个独立的工作目录,每个有自己的分支。Alice 在 .worktrees/auth-refactor/ 下工作,Bob 在 .worktrees/ui-login/ 下工作——互不干扰。
沿用 S17 的教学版 MessageBus、协议和自治认领机制。本章新增:
工作原理
创建:任务-Worktree 绑定
绑定规则:一个任务绑定一个 worktree。绑定不改任务状态——任务仍是 pending,队友自动认领时才推进到 in_progress。这样 Lead 可以提前创建任务和 worktree,队友 idle 时自然认领带 worktree 的任务。
队友工具的 cwd 切换
教学版给每个队友维护一个 wt_ctx 字典,记录当前 worktree 路径。队友认领带 worktree 的任务时,wt_ctx 自动设置为 worktree 路径;队友的 bash、read_file、write_file 在 worktree 目录下执行:
这是教学简化。真实 CC 的 EnterWorktree 用 process.chdir() 切换整个进程目录,AgentTool isolation 用 cwdOverride 包住子 agent 执行。
收尾:Keep 还是 Remove
任务完成后,两个选择:
Keep = 留着分支,等人工 review 后合并到主分支。Remove = 有改动时默认拒绝,需要 discard_changes=true 确认。不自动 complete task——任务完成由队友的 complete_task 显式触发。
事件流:可审计
每次生命周期操作写入日志,方便排查:
事件类型:create(创建)、remove(删除)、keep(保留)。教学版只记录事件用于人工排查;完整恢复还需要 index 或 git worktree list 扫描。
run_git:返回成功/失败
create_worktree 和 remove_worktree 只在 git 命令成功后才写事件日志,保证日志反映真实状态。
相对 s17 的变更
试一下
试试这个 prompt:
Create two tasks, then create worktrees for each (bind with task_id). Spawn alice and bob. Watch them auto-claim and work in isolated directories.
观察重点:两个 worktree 的 git status 输出是否显示不同的分支?队友认领带 worktree 的任务后,bash 命令是否在 worktree 目录下执行?remove_worktree 对有改动的 worktree 是否拒绝?.tasks/ 中的任务在绑定后状态是否仍为 pending?
接下来
Agent 团队能在隔离的工作空间中自组织了。但 Agent 的能力受限于我们给它写的工具——bash、read、write、task...
如果用户已经有了自己的工具怎么办?比如一个公司内部的 Jira API、一个自建的部署系统?
s19 MCP Plugin → 给 Agent 装一个插件系统。外部工具通过标准协议接入,Agent 不需要知道它们是谁写的。
深入 CC 源码
CC 的 worktree 系统有两条路径:EnterWorktree(当前会话切入)和 AgentTool isolation(子 agent 隔离)。
EnterWorktree:当前会话切换
EnterWorktreeTool.ts:92-97 创建 worktree 后立即 process.chdir(worktreePath)、setCwd()、setOriginalCwd()、saveWorktreeState()。当前会话的工作目录直接切换到 worktree——不是 prompt 提醒,而是进程级目录变更。
ExitWorktreeTool.ts:261-320 的 keep/remove 都会 restoreSessionToOriginalCwd() 恢复原目录。Remove 时检查未提交改动(ExitWorktreeTool.ts:190-220),没有 discard_changes: true 就拒绝删除。
AgentTool isolation:子 agent 隔离
AgentTool.tsx:590-641 在 isolation: "worktree" 时调用 createAgentWorktree() 创建 worktree,用 cwdOverridePath 包住子 agent 执行。子 agent 的所有操作自动在 worktree 目录下进行。AgentTool/prompt.ts:272 告诉模型:这是临时 worktree,无改动自动清理,有改动返回路径和分支。
worktree.ts:902-951 的 createAgentWorktree() 不修改全局 session cwd,只给子 agent 用。worktree.ts:961-1020 的 removeAgentWorktree() 从主 repo root 删除。
name 校验
worktree.ts:76-84 校验 slug:拒绝 ./..,允许 [a-zA-Z0-9._-]。worktree.ts:48 定义 VALID_WORKTREE_SLUG_SEGMENT。教学版的 validate_worktree_name 用同样的规则。
路径和分支命名
真实路径是 .claude/worktrees/,分支名 worktree-{slug}(worktree.ts:204-227,斜杠用 + 替代)。教学版用 .worktrees/ 和 wt/{name} 简化。
创建时用 git worktree add -B(worktree.ts:326-328),优先基于 origin/<defaultBranch> 而非当前 HEAD。
状态管理
CC 没有 task-worktree 绑定。Worktree 状态通过 PersistedWorktreeSession(worktree.ts:756-768)管理,字段包括 originalCwd、worktreePath、worktreeName、worktreeBranch、originalBranch、originalHeadCommit、sessionId 等——没有 taskId。saveWorktreeState()(sessionStorage.ts:2883-2920)以 type: 'worktree-state' 写入 session transcript。
教学版用 task 的 worktree 字段做绑定,是教学简化。CC 把 worktree 和 task 作为两个独立系统,通过 Agent 理解上下文来关联。
