Worktree + Task Isolation
CollaborationIsolate by Directory
同一项研究要并行维护几个稳健性方向时,每个方向需要独立的目录与独立的 git 分支,多个 agent 同时各做各的不互相干扰。Claude Code 用 git 提供的"多目录"机制让每个稳健性版本住在独立目录里,几个 agent 同时各跑各的回归互不冲突。
β=0.0120* 显著、规模比 0-1 版大 30 倍)、pc-esg-subscores/ 跑 E/S/G 三分项(拆解被解释变量为 e_score01/s_score01/g_score01)。三个版本核心数据相同,只是 do6_baseline.do 里 LHS 替换或拆解。
s01 > s02 > s03 > s04 > s05 > s06 | s07 > s08 > s09 > s10 > s11 > [ s12 ]
"Each works in its own directory, no interference" -- tasks manage goals, worktrees manage directories, bound by ID.
Harness layer: Directory isolation -- parallel execution lanes that never collide.
Problem
By s11, agents can claim and complete tasks autonomously. But every task runs in one shared directory. Two agents refactoring different modules at the same time will collide: agent A edits config.py, agent B edits config.py, unstaged changes mix, and neither can roll back cleanly.
The task board tracks what to do but has no opinion about where to do it. The fix: give each task its own git worktree directory. Tasks manage goals, worktrees manage execution context. Bind them by task ID.
Solution
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
How It Works
- Create a task. Persist the goal first.
TASKS.create("Implement auth refactor")
# -> .tasks/task_1.json status=pending worktree=""
- Create a worktree and bind to the task. Passing
task_idauto-advances the task toin_progress.
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"
The binding writes state to both sides:
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)
- Run commands in the worktree.
cwdpoints to the isolated directory.
subprocess.run(command, shell=True, cwd=worktree_path,
capture_output=True, text=True, timeout=300)
- Close out. Two choices:
worktree_keep(name)-- preserve the directory for later.worktree_remove(name, complete_task=True)-- remove directory, complete the bound task, emit event. One call handles teardown + completion.
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", ...)
- Event stream. Every lifecycle step emits to
.worktrees/events.jsonl:
{
"event": "worktree.remove.after",
"task": {"id": 1, "status": "completed"},
"worktree": {"name": "auth-refactor", "status": "removed"},
"ts": 1730000000
}
Events emitted: worktree.create.before/after/failed, worktree.remove.before/after/failed, worktree.keep, task.completed.
After a crash, state reconstructs from .tasks/ + .worktrees/index.json on disk. Conversation memory is volatile; file state is durable.
What Changed From s11
| Component | Before (s11) | After (s12) |
|---|---|---|
| Coordination | Task board (owner/status) | Task board + explicit worktree binding |
| Execution scope | Shared directory | Task-scoped isolated directory |
| Recoverability | Task status only | Task status + worktree index |
| Teardown | Task completion | Task completion + explicit keep/remove |
| Lifecycle visibility | Implicit in logs | Explicit events in .worktrees/events.jsonl |
Try It
cd claude-code-for-researchers
python agents/s12_worktree_task_isolation.py
Create tasks for "ESG-main 0-1 primary" and "ESG-discrete 1-9 robustness", then list tasks.Create worktree "pc-esg-main" for task 1, then bind task 2 to a new worktree "pc-esg-discrete".Run "stata-mcp do do6_baseline.do" in worktree "pc-esg-main".Keep worktree "pc-esg-discrete", then list worktrees and inspect events.Remove worktree "pc-esg-main" with complete_task=true, then list tasks/worktrees/events.