learn-claude-code s12 解析:Worktree + 任务隔离,用 Git Worktree 构建永不碰撞的 Agent 并行执行通道
2026/9/7 2:24:58 网站建设 项目流程

learn-claude-code s12 解析:Worktree + 任务隔离,用 Git Worktree 构建永不碰撞的 Agent 并行执行通道

【免费下载链接】learn-claude-codeBash is all you need - A nano claude code–like 「agent harness」, built from 0 to 1项目地址: https://gitcode.com/GitHub_Trending/an/learn-claude-code

本篇指南基于 learn-claude-code("Bash is all you need" 的 nano claude-code agent harness 教学仓库)中第 s12 课的核心文档,深入讲解如何用 git worktree 为每个任务分配独立的执行目录,解决多 Agent 并行开发时的文件互相污染问题。读完后,你将理解"任务控制平面 + 目录执行平面"的双状态机设计、任务与 worktree 的 ID 绑定机制、生命周期事件流的实现细节,并能在真实仓库中运行这套隔离方案。

1. 问题背景:共享目录下的并行碰撞

s12 处于仓库旧版 12 课渐进式课程线的终点附近:到 s11 为止,Agent 已经具备自主认领(claim)和完成任务的能力,任务板(task board)负责"做什么"。但所有任务都运行在同一个共享目录里,文档中给出了一个典型的失败场景:

两个 Agent 同时重构不同模块——Agent A 改config.py,Agent B 也改config.py,未提交的改动互相混合(unstaged changes mix),谁也没法干净地回滚。

任务板只追踪what to do,对where to do it没有任何约束。s12 的解法一句话概括:给每个任务一个独立的 git worktree 目录,任务管目标,worktree 管执行上下文,用任务 ID 把两者绑定起来("Isolate by directory, coordinate by task ID")。

对应实现位于 agents/s12_worktree_task_isolation.py,英文文档见 docs/en/s12-worktree-task-isolation.md,中文对照见 docs/zh/s12-worktree-task-isolation.md。

2. 整体架构:双平面 + 双状态机

文档给出的架构全景图如下,左半部分是控制平面.tasks/,任务状态),右半部分是执行平面.worktrees/,真实的工作目录),中间通过 task_id 双向关联:

Control plane (.tasks/) Execution plane (.worktrees/) +------------------+ +------------------------+ | task_1.json | | auth-refactor/ | | status: in_progress <------> branch: wt/auth-refactor | worktree: "auth-refactor" | task_id: 1 | +------------------+ +------------------------+ | task_2.json | | ui-login/ | | status: pending <------> branch: wt/ui-login | worktree: "ui-login" | task_id: 2 | +------------------+ +------------------------+ | index.json (worktree registry) events.jsonl (lifecycle log) State machines: Task: pending -> in_progress -> completed Worktree: absent -> active -> removed | kept

两个状态机分别管理各自的生命周期,磁盘上的三类持久化文件是恢复的依据:

文件角色
.tasks/task_N.json每个任务一个 JSON 文件,含idsubjectstatusworktree绑定字段
.worktrees/index.jsonworktree 注册表,记录名称、路径、分支、task_id、状态
.worktrees/events.jsonl追加式生命周期事件日志

从源码结构看,崩溃后不需要会话内存——.tasks/+.worktrees/index.json即可重建全部现场。文档的原话是:"Conversation memory is volatile; file state is durable."(会话记忆是易失的,磁盘状态是持久的。)

3. 工作原理:五步完整流程

3.1 第一步:先创建任务,持久化目标

TASKS.create("Implement auth refactor") # -> .tasks/task_1.json status=pending worktree=""

TaskManager 的实现细节:

  • 任务 ID 通过扫描目录下已有的task_*.json取最大 ID + 1 得到(_max_id),天然支持崩溃后重启续编号;
  • 每个任务文件包含idsubjectdescriptionstatus(初始pending)、ownerworktree(初始空串)、blockedBycreated_at/updated_at等字段(见create);
  • status只允许pending/in_progress/completed三个值,update方法会显式校验非法状态并抛出ValueError(源码)。

3.2 第二步:创建 worktree 并绑定任务

WORKTREES.create("auth-refactor", task_id=1) # -> git worktree add -b wt/auth-refactor .worktrees/auth-refactor HEAD # -> index.json gets new entry, task_1.json gets worktree="auth-refactor"

传入task_id会自动把任务从pending推进到in_progress。绑定逻辑的核心代码(文档摘录,与 TaskManager.bind_worktree 实现一致):

def bind_worktree(self, task_id, worktree): task = self._load(task_id) task["worktree"] = worktree if task["status"] == "pending": task["status"] = "in_progress" self._save(task)

WorktreeManager.create 的完整实现包含多层防护,比文档示例更丰富:

  1. 名称校验re.fullmatch(r"[A-Za-z0-9._-]{1,40}", name),只允许 1–40 个字符的字母、数字、._-,防止路径注入;
  2. 查重:若index.json中已存在同名 worktree 直接报错;
  3. 任务存在性校验:传了task_id但任务不存在时报错;
  4. 执行 git 命令git worktree add -b wt/<name> .worktrees/<name> <base_ref>,分支统一加wt/前缀,base_ref默认为HEAD(可传master、某个 commit 等);
  5. 写注册表 + 回写任务:先追加 entry 到index.json(含namepathbranchtask_idstatus: "active"created_at),再调用tasks.bind_worktree回写任务文件;
  6. 事件三连:成功路径发worktree.create.beforeworktree.create.after,任何异常则发worktree.create.failed并向上抛出。

注意一个从源码结构可以看出的一致性策略:create失败时不会留下半绑定状态——index 只在 git 成功后写入,任务绑定也紧随其后,异常直接抛出由上层(agent loop 的 handler)捕获为错误文本。

3.3 第三步:在 worktree 中执行命令

subprocess.run(command, shell=True, cwd=worktree_path, capture_output=True, text=True, timeout=300)

对应WorktreeManager.run,隔离的本质就是cwd参数指向了隔离目录。实现的额外细节:

  • 命令先经过一个危险命令黑名单过滤(rm -rf /sudoshutdownreboot> /dev/),命中即返回Error: Dangerous command blocked
  • worktree 名称不存在或路径被删时返回明确错误,而不是静默执行;
  • 超时 300 秒,超时返回Error: Timeout (300s)
  • 输出合并 stdout + stderr 后截断到 50000 字符,防止撑爆上下文窗口。

配套的status方法(源码)在指定 worktree 内执行git status --short --branch,工作区干净时返回 "Clean worktree"。

3.4 第四步:收尾——keep 或 remove

任务结束后有两个显式出口:

  • worktree_keep(name):目录保留供后续使用,index.json中状态置为kept并记录kept_at(源码),同时发出worktree.keep事件;
  • worktree_remove(name, complete_task=True):删除目录、完成绑定任务、发出事件,一个调用搞定"拆除 + 完成"。

文档摘录的remove核心逻辑与 WorktreeManager.remove 一致:

def remove(self, name, force=False, complete_task=False): self._run_git(["worktree", "remove", wt["path"]]) if complete_task and wt.get("task_id") is not None: self.tasks.update(wt["task_id"], status="completed") self.tasks.unbind_worktree(wt["task_id"]) self.events.emit("task.completed", ...)

实际源码在此之外还做了三件事:force=True时给 git 追加--force参数;拆除后把 index 中对应条目的status置为removed并记录removed_at(条目保留而非删除,注册表可追溯历史);失败时发worktree.remove.failed事件。注意complete_task会同时调用unbind_worktree清空任务上的worktree字段,保持两侧引用一致。

3.5 第五步:事件流(Event Bus)

每个生命周期步骤都追加写入.worktrees/events.jsonl,例如:

{ "event": "worktree.remove.after", "task": {"id": 1, "status": "completed"}, "worktree": {"name": "auth-refactor", "status": "removed"}, "ts": 1730000000 }

EventBus 是 append-only 的:emit{event, ts, task, worktree[, error]}序列化为一行 JSON 追加到文件;list_recent(limit)读取最后 N 行(钳制在 1–200 之间),解析失败的行会标记为parse_error而不是抛异常。完整事件类型清单:

  • worktree.create.before/worktree.create.after/worktree.create.failed
  • worktree.remove.before/worktree.remove.after/worktree.remove.failed
  • worktree.keep
  • task.completed

4. 对模型暴露的工具面

s12 的 agent loop(agent_loop)把上述能力封装为 17 个工具注册进TOOLS列表和TOOL_HANDLERS分发表,分为四组:

工具说明
基础bash/read_file/write_file/edit_file与工作区同风格的原子文件与 shell 工具,bash超时 120s、同样有危险命令过滤
任务平面task_create/task_list/task_get/task_update/task_bind_worktree任务板 CRUD;task_list输出形如[>] #1: subject owner=x wt=auth-refactor,一眼看到状态、负责人和 worktree 绑定
执行平面worktree_create/worktree_list/worktree_status/worktree_run/worktree_keep/worktree_remove每个 worktree 操作都受 index.json 约束,worktree_remove支持forcecomplete_task布尔参数
可观测worktree_events读取最近 N 条生命周期事件

系统提示词(SYSTEM)明确引导模型的行为模式:"For parallel or risky changes: create tasks, allocate worktree lanes, run commands in those lanes, then choose keep/remove for closeout."——即把 worktree 当作"并行执行通道"(execution lanes)来使用。

5. 相对 s11 的变化

文档的对比表完整继承了 s12 的增量价值,这里原文保留:

ComponentBefore (s11)After (s12)
CoordinationTask board (owner/status)Task board + explicit worktree binding
Execution scopeShared directoryTask-scoped isolated directory
RecoverabilityTask status onlyTask status + worktree index
TeardownTask completionTask completion + explicit keep/remove
Lifecycle visibilityImplicit in logsExplicit events in.worktrees/events.jsonl

6. 运行与验证

6.1 环境要求

  • Python 依赖见 requirements.txt:anthropic>=0.25.0python-dotenv>=1.0.0pyyaml>=6.0
  • 环境变量:脚本通过load_dotenv(override=True)加载.env,必须设置MODEL_ID(源码第 50 行,缺失会直接 KeyError),API key 走ANTHROPIC_API_KEY,可选ANTHROPIC_BASE_URL指向兼容端点;
  • git 是硬前提:启动时detect_repo_rootgit rev-parse --show-toplevel定位仓库根,WorktreeManager再用git rev-parse --is-inside-work-tree检查git_available。不在 git 仓库内时脚本仍能启动,但所有worktree_*工具会返回 "Not in a git repository. worktree tools require git." 错误。

6.2 运行

cd learn-claude-code python agents/s12_worktree_task_isolation.py

启动后进入交互终端(提示符s12 >>),文档建议依次输入以下五个 prompt(英文 prompt 效果通常更好,也可用中文):

  1. Create tasks for backend auth and frontend login page, then list tasks.
  2. Create worktree "auth-refactor" for task 1, then bind task 2 to a new worktree "ui-login".
  3. Run "git status --short" in worktree "auth-refactor".
  4. Keep worktree "ui-login", then list worktrees and inspect events.
  5. Remove worktree "auth-refactor" with complete_task=true, then list tasks/worktrees/events.

这五步恰好覆盖"创建 → 绑定 → 隔离执行 → 保留 → 拆除+完成"的完整生命周期,运行结束后检查.tasks/.worktrees/index.json.worktrees/events.jsonl即可验证每一步的落盘状态。

7. 与当前 17 课体系的衔接

需要说明版本背景:README.md 记录了课程的重构映射——旧版 12 课中的 "Task-bound worktrees"(old s12)在新 17 课体系中被并入s13 Agent Teams("persistent teammates / atomic task claims / task-bound worktrees / typed protocols"),README 在 Claude Code 架构拆解中也把 "task-bound worktrees for parallel edits" 列为 harness 的组成部分。也就是说,s12 这套 worktree 隔离机制并没有被抛弃,而是作为多 Agent 协作(s13)的一项基础能力被延续。

从测试代码可以印证这一演进:tests/test_agent_teams_runtime.py 中存在大量 worktree 相关用例,例如队友持有过期 worktree 分配时的容错(test_teammate_survives_stale_worktree_assignment)、脏工作区默认拒绝删除(test_remove_worktree_refuses_dirty_checkout_by_default)、非法路径(../escape)永远不可认领(test_invalid_or_unregistered_worktree_never_becomes_claimable)等。可以推断,s12 在单机场景建立的"注册表 + 状态机 + 事件流"三件套,是 s13 多 Agent 场景下更复杂治理规则的地基。深入该主题可继续阅读 s13_agent_teams/README.md。

8. 要点回顾

  • 分离两个平面.tasks/管目标与状态(控制平面),.worktrees/管目录与分支(执行平面),用 task_id 双向绑定;
  • 绑定即推进create(name, task_id=...)一次调用完成 git worktree 创建、index 登记、任务状态pending → in_progress三件事,绑定写两侧;
  • 隔离靠 cwd:执行工具只是把subprocess.runcwd指向 worktree 路径,配合 300s 超时、50000 字符截断和危险命令过滤;
  • 显式收尾keep保留 /remove(complete_task=True)拆除并完成任务,index 中留下kept/removed痕迹供审计;
  • 事件可观测 + 状态可恢复events.jsonl记录全部 before/after/failed 事件;崩溃后凭磁盘文件即可重建,无需依赖会话记忆。

这套"目录级隔离"模式的最小实现不足 800 行(含 agent loop 与工具 schema),是构建任何多任务并行 Agent harness 时值得直接借鉴的参考设计。

【免费下载链接】learn-claude-codeBash is all you need - A nano claude code–like 「agent harness」, built from 0 to 1项目地址: https://gitcode.com/GitHub_Trending/an/learn-claude-code

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询