Worktree + Task Isolation
s07 的任务板管"做什么",但不管"在哪做"。
s12 用 Git Worktree 给每个任务一个独立目录——用 task_id 把控制面和执行面绑定在一起。
s11 的 Agent 已经能自主干活——还缺什么?
到 s11,Agent 已经能扫描任务池、认领任务、自主执行。但所有任务共享一个目录。两个 Agent 同时重构不同模块——A 改 config.py,B 也改 config.py,未提交的改动互相污染,谁也没法干净回滚。
s11:共享目录
🔹 任务板只管"做什么"
🔹 没有"在哪做"的概念
🔹 Agent A 和 B 在同一个目录改文件
🔹 未提交的改动互相覆盖
🔹 无法单独回滚某个任务
s12:任务-目录绑定
🔹 控制面(.tasks/)管"做什么"
🔹 执行面(.worktrees/)管"在哪做"
🔹 每个任务一个独立 git worktree 目录
🔹 用 task_id 把两面绑在一起
🔹 每个任务的改动在独立分支,干净回滚
不只是"文件冲突"——共享目录的三个深层问题
① 测试污染:Agent A 跑测试时,目录里有 Agent B 未完成的改动。测试结果不可信。
② 回滚灾难:A 的改动有问题要 git reset --hard,但 B 的改动也在里面——怎么只回滚 A?
③ 崩溃恢复缺失:Agent 崩溃后,共享目录是脏的。"谁改了哪些文件?哪些是已完成任务的,哪些是进行中的?"——没有答案,因为没有把任务和目录关联起来。
解决方案:双面 — 控制面 + 执行面
s12 的核心结构:两个平面通过 task_id ↔ worktree name 绑定。任务从 pending → in_progress → completed,worktree 从 absent → active → removed | kept。
title: "Implement auth refactor"
status: in_progress
worktree: "auth-refactor"
owner: "alice"
task_2.json
title: "Build UI login page"
status: pending
worktree: ""
owner: ""
branch: wt/auth-refactor
task_id: 1
ui-login/
branch: wt/ui-login
task_id: 2
index.json (registry)
events.jsonl (日志)
两个状态机,一个绑定
pending
in_progress
completed
absent
active
removed | kept
两个状态机独立但联动。当 worktree 被创建并绑定任务 → 任务自动从 pending 推进到 in_progress。当 worktree 被 remove 且 complete_task=true → 任务从 in_progress 推进到 completed。
和 s07 的任务图是什么关系?
s07 的任务文件(.tasks/task_*.json)新增一个字段:"worktree": "auth-refactor"。之前 s07 只管 status、owner、blockedBy——现在多了一个 worktree 字段记录"这个任务在哪个目录里执行"。同一个 task_*.json 文件,s12 只是多写了一个字段。
向后兼容:老任务的 worktree 字段是空字符串——就是 s11 的行为(共享目录)。新任务带上 worktree 字段就享受隔离。
创建 Worktree + 绑定任务:一步到位
create():创建目录 + 创建分支 + 绑定任务
bind_worktree():写入两侧状态
bind_worktree 是 s12 的引擎——它同时做了两件事:① 在 task 上记录 worktree 字段(控制面知道自己映射到哪个执行面);② 把 pending 任务推进到 in_progress(worktree 创建 = 任务开始执行)。一个函数调用,两侧状态同步写入。
在 worktree 里执行:cwd 隔离,Agent 无感
Agent 不需要知道自己在一个 worktree 里。它照常调 Bash 工具执行命令——但 cwd 指向了隔离目录。
subprocess.run 的 cwd 参数
Agent 的视角:Agent 调 bash("python test.py"),看到的输出是 worktree 里的测试结果。Agent 读文件、写文件——cwd 保证这些操作都在隔离目录里。对 Agent 的代码逻辑零侵入。
对比:s11 的相同命令在共享目录执行(cwd 是主项目路径)。s12 只改了一行——cwd 指向 worktree。一行的改动,隔离了整个执行环境。
🔬 不止文件隔离——分支也隔离
每个 worktree 在独立分支上(wt/auth-refactor)。Agent 在 worktree 里做 git add + git commit 只影响自己的分支。不会污染 main 分支,也不会看到其他 Agent 未合并的 commit。
这意味着一件事:Lead 可以逐个审查每个 Agent 的工作成果——git log wt/auth-refactor 看 Alice 做了哪些 commit,git diff main..wt/auth-refactor 看她改了什么。Agent 的工作变成了可审查、可单独合并的 Git 分支。
收尾:keep 保留 vs remove 删除 + 完成任务
任务做完后,worktree 有两种命运——保留供后续使用,或删除并完成绑定任务。
worktree_keep(name)
🔹 保留目录和分支
🔹 任务状态不变
🔹 后续可以再进入继续工作
🔹 适用:任务需要多轮迭代
worktree_remove(name, complete_task=True)
🔹 删除目录
🔹 自动把绑定任务标为 completed
🔹 一个调用搞定拆除 + 完成
🔹 发出 task.completed 事件
remove():拆除 + 完成任务 + 发出事件
一个调用,三件事:拆除 worktree + 完成任务 + 发出事件。不是三个独立的步骤(容易遗漏)——一个入口保证三件事原子地发生在同一个调用里。
events.jsonl:显式的生命周期日志
s11 的 Agent 在后台做事,Lead 很难知道"现在进度如何?Alice 的 worktree 创建成功了吗?Bob 的任务完成了吗?"——s12 用 events.jsonl 显式记录每个生命周期步骤。
事件类型:覆盖完整生命周期
事件流的三个用途
① 调试:Agent 行为异常?tail -f .worktrees/events.jsonl 实时看生命周期流转。哪个 step 卡住了,一眼就知道。
② 崩溃恢复:Agent 崩溃了,但 worktree.create.after 事件已经写入——重启后知道"上次创建到一半,需要清理遗留 worktree"。
③ 审计:谁在什么时候创建了哪个 worktree?哪个任务什么时候完成的?events.jsonl 就是 Agent 团队的 audit log。
⭐ 事件类型完整列表:worktree.create.before、worktree.create.after、worktree.create.failed、worktree.remove.before、worktree.remove.after、worktree.remove.failed、worktree.keep、task.completed。
崩溃恢复 & 代码拆解
崩溃后从磁盘重建现场
Agent 的会话(messages)是易失的——崩溃了就没了。但文件是持久的:
.tasks/ 知道"任务 #1 的状态是 in_progress,绑定了 worktree auth-refactor"。
.worktrees/index.json 知道"auth-refactor worktree 在哪个路径、在哪个分支"。
.worktrees/events.jsonl 知道"最后一条事件是 worktree.remove.before 还是 after?"
重启后,不需要 Agent 的上下文记忆——读这三个文件,就能完整重建现场:哪些任务进行中、哪些 worktree 需要清理、哪些分支有未合并的 commit。
WorktreeManager(~80 行)
create() + bind_worktree() + remove() + keep() + list()。管理 .worktrees/ 目录下的 index.json 和 events.jsonl。
Task schema 升级(1 个字段)
task_*.json 新增 "worktree": "" 字段。s07 的任务结构向后兼容——空字符串 = 共享目录(s11 行为),非空 = 隔离 worktree(s12 行为)。
Teammate Loop 改动(~6 行)
spawn/claim 时调 WORKTREES.create(name, task_id=id),agent loop 末尾接 keep 或 remove。和 s09/s11 的集成点。
events.jsonl 管道(~15 行)
emit() 往 events.jsonl 追加一行 JSON。所有生命周期变更都经过它——可观测、可审计、可恢复。
| 组件 | s11 | s12 |
|---|---|---|
| 协调 | 任务板 (owner/status) | 任务板 + worktree 显式绑定 |
| 执行范围 | 共享目录 | 每个任务独立目录 |
| 可恢复性 | 仅任务状态 | 任务状态 + worktree index + events |
| 收尾 | 任务完成 | 任务完成 + 显式 keep/remove |
| 生命周期可见性 | 隐式日志 | events.jsonl 显式事件流 |
从 s12 带走的四个核心认识
双面绑定
控制面管"做什么",执行面管"在哪做"。task_id 是两面的桥梁。bind_worktree 一步同步两侧状态。
事件流 = 可观测性
events.jsonl 不复杂——就是追加 JSON 行。但有了它,Agent 的生命周期从"黑盒"变成了"可审计"。
隔离代替协调
共享目录 → 需要锁和协议(s10)。隔离目录 → 冲突不发生。对 Agent 系统,隔离的成本远低于协调的成本。
磁盘 > 会话
会话记忆易失,磁盘状态持久。崩溃后从 .tasks/ + .worktrees/index.json + events.jsonl 重建现场。不依赖任何内存状态。
落地案例:Worktree 隔离在真实系统中的应用
📋 Claude Code 的 EnterWorktree / ExitWorktree
Claude Code 的 EnterWorktree 和 ExitWorktree 工具就是 s12 的生产实现。当你让 Claude Code "在 worktree 里做这个改动",它在 .claude/worktrees/ 下创建隔离的 git worktree,在新目录里完成所有修改,commit,然后通过 ExitWorktree 清理或保留。
整个过程和 s12 完全一致:create → bind → execute with cwd → keep/remove → emit events。你每次用 worktree 功能都是在经历 s12 的完整生命周期。
🔄 GitHub Actions 的 Job Runner
GitHub Actions 的每个 workflow job 跑在独立的 runner 上——checkout 同一份代码的副本,独立修改、测试,最后通过 PR 回传。这和 s12 的"每个任务一个 worktree"是同构的——每个 job = 一个隔离的执行环境 = 一个 task 绑定一个 worktree。
🏗️ Git 本身的分布式哲学
s12 的双面架构(控制面 + 执行面)就是 Git 分布式模型的微缩版。Git 的核心假设是"每个人在本地仓库工作,通过分支和 merge 同步"。s12 只不过把这个模型搬到了单机多 Agent 的场景——每个 worktree 就是一个"本地仓库",task 就是"工作目标"。Git 花了 20 年证明这套模型适合人类团队——s12 证明它同样适合 Agent 团队。
🎯 12 节课程完整图景
| 模块 | 课程 | 一句话总结 |
| 基础循环 | s01-s04 | Agent 怎么干活——循环 + 工具 + 外部记忆 + 子 Agent |
| 知识上下文 | s05-s06 | 怎么按需加载技能 + 怎么压缩释放上下文 |
| 任务与团队 | s07-s09 | 持久化任务图 + 后台执行 + 多 Agent 邮箱通信 |
| 隔离与治理 | s10-s12 | 协作协议 + 自主认领 + Worktree 文件隔离 |
从 while True 出发,走过 12 节课,你现在站在一个可治理的多 Agent 系统的最顶层。循环 → 工具 → 记忆 → 委派 → 技能 → 压缩 → 任务图 → 后台 → 团队 → 协议 → 自主 → 隔离。每一层解决一个问题,每一层为下一层打基础。
工程不是学完的,是改完的。
去读 Claude Code 源码验证你的理解,用这些模式改造你的 Agent 项目,或设计全新的多 Agent 系统。
动手吧。