03 · 迭代 / 任务 / Worktree1 迭代 = 1 worktree = 1 branch = 1 PR,迭代可拆多个 task 串行执行
核心模型
工作单元分层
Iteration(迭代) = 一个完整的可发布/可合并的变更单元 = 1 PR
Task(任务) = 迭代里的一个具体子活 = 一个 commit / 一组 commit
Worktree = 迭代期间的物理隔离目录 = 1 branch 的独立 checkout
Task(任务) = 迭代里的一个具体子活 = 一个 commit / 一组 commit
Worktree = 迭代期间的物理隔离目录 = 1 branch 的独立 checkout
| 概念 | 数量关系 | 物理形态 |
|---|---|---|
| Iteration | 1 | 1 个 worktree/iter-001-xxx/ 目录,对应 1 个 branch(如 feat/iter-001-login),1 个 PR |
| Task | 1 ~ N(可拆) | 在 worktree 内的串行 commit,全部进同一个 branch / PR |
| Worktree | 同 iteration 数 | 迭代开始时建,迭代结束(merge 后)清理 |
Worktree 怎么用
每个 iteration 启动时,PM 创建 worktree:
# 项目根目录
~/agent-workspace/myapp/
# iteration 启动时,PM 执行:
git worktree add ../myapp.iter-001-login -b feat/iter-001-login main
# 目录结构变成:
~/agent-workspace/
├── myapp/ # 主目录(main 分支)
│ └── .pm/ # PM 元数据(在主目录)
└── myapp.iter-001-login/ # iteration worktree
├── .git # 指向主仓库的 file
└── src/ ... # feat/iter-001-login 分支
Developer agent 拿到 workdir=~/agent-workspace/myapp.iter-001-login 后,所有操作都发生在这个隔离目录里。
为什么 worktree 要按 iteration 分(而不是按 task)
- Task 太细—— 大部分 task 之间紧耦合(比如"建表"和"写 API"),串行 commit 更合理
- Iteration 才是可发布单元—— 用户 review 一次,合一次,而不是 5 个 PR 合 5 次
- 多 iteration 可以真并行—— A 迭代在 worktree A 跑,B 迭代可以同时在 worktree B 跑,不冲突
- Worktree 物理隔离—— agent 不会"看错"主目录的代码
Iteration 状态机
todo
→
in_progress
→
pr_open
→
in_review
→
approved
→
merging
→
done
各状态转移条件见下表。
| 状态 | 含义 | 进入条件 | 进入动作 |
|---|---|---|---|
| todo | PM 刚建好 iteration 记录,还没开始 | 用户提需求,PM 决定开新迭代 | 写 .pm/iterations.json,建 worktree |
| in_progress | Developer 在干活 | PM 派 developer session | 发任务给 developer,等结果 |
| pr_open | PR 已开,等用户看到 | developer 推了 branch + gh pr create |
PM 发微信通知用户,启 reviewer |
| in_review | Reviewer 在审 | PM 派 reviewer session | 发 PR URL + 任务说明给 reviewer |
| approved | Reviewer 给 approve,等用户拍板 | reviewer verdict = approve | PM 通知用户"可以合了" |
| merging | Merger 在合 | 用户说"合" | PM 派 merger session |
| done | 已合,worktree 已清 | merger 报告 merge 完成 + 清理完成 | PM 更新 .pm/iterations.json,发总结给用户 |
| failed | 任何阶段 PM 决定放弃 | 3 次重试失败 / 用户取消 / 预算耗尽 | PM 写失败原因,清 worktree |
从 approved 转 changes_requested
如果 reviewer 给 request_changes,iteration 回退,但不是回到 todo。具体怎么处理由 PM 决定:
- 小问题(错别字、漏注释)→ PM 让 developer 在同一个 worktree 修(状态回到
in_progress) - 大问题(架构/产品)→ PM 报用户决定
- 反复 reject → iteration 标
failed,让用户重启
Task 状态机(iteration 内部)
Task 没有自己独立的状态机,跟随 iteration 流转。每个 task 在 .pm/iterations.json 里有一条记录,跟踪 developer session 引用、commit、备注。
| Task 状态 | 含义 |
|---|---|
| todo | PM 已拆,developer 还没开始 |
| in_progress | developer 正在写这个 task |
| done | developer 报告完成,有 commit |
| failed | developer 3 次重试都失败,需要 PM/用户决策 |
| cancelled | PM 决定不做这个 task(比如合并到其他 task) |
Task 执行策略:串行 vs 并行
默认串行。原因:worktree 共享,多个 developer 并行会写冲突。
只有在以下条件满足时 PM 才并行:
- Task 之间无文件依赖(比如"写 README"和"加 CI 配置")
- Task 都在不同目录
- 有足够资源(本机 4G 内存,并行 2 个 session 已经是上限)
Iteration 命名规范
id: iter-NNN-slug 例: iter-001-login
branch: feat/iter-NNN-slug 例: feat/iter-001-login
worktree: ../<project>.iter-NNN-slug 例: ../myapp.iter-001-login
PR title: "<title> (PM-iter-NNN)" 例: "实现用户登录 (PM-iter-001)"
Task 命名规范
id: task-NNN-slug 例: task-001-build-user-table
commit: "task-NNN: <msg>" 例: "task-001: add user table migration"
.pm/iterations.json 结构
{
"version": 1,
"project": "myapp",
"github": { "owner": "netkingcode", "repo": "myapp" },
"iterations": [
{
"id": "iter-001-login",
"title": "实现用户登录",
"status": "in_review",
"branch": "feat/iter-001-login",
"worktree": "../myapp.iter-001-login",
"pr_url": "https://github.com/netkingcode/myapp/pull/1",
"pr_number": 1,
"created_at": "2026-06-19T00:00:00Z",
"updated_at": "2026-06-19T01:30:00Z",
"developer_model": "opencode-go/deepseek-v4-pro",
"reviewer_model": "opencode-go/glm-5.2",
"developer_session": "ses_xxx1",
"reviewer_session": "ses_xxx2",
"merger_session": null,
"tasks": [
{
"id": "task-001-user-table",
"title": "建 user 表 + migration",
"status": "done",
"developer_session": "ses_xxx1a",
"commit_sha": "abc1234",
"deliverable": "db/migrate/20260619_create_users.rb + app/models/user.rb"
},
{
"id": "task-002-login-api",
"title": "POST /api/login 接口",
"status": "done",
"developer_session": "ses_xxx1b",
"commit_sha": "def5678",
"deliverable": "app/controllers/api/sessions_controller.rb"
},
{
"id": "task-003-login-ui",
"title": "前端登录页面",
"status": "done",
"developer_session": "ses_xxx1c",
"commit_sha": "ghi9012",
"deliverable": "app/views/sessions/new.html.erb"
},
{
"id": "task-004-integration-test",
"title": "端到端集成测试",
"status": "in_progress",
"developer_session": "ses_xxx1d"
}
],
"review": {
"verdict": "request_changes",
"blockers": ["缺 rate limiting"],
"comments_count": 3,
"review_url": "https://github.com/netkingcode/myapp/pull/1#pullrequestreview-xxx"
},
"cost_usd": 0.12,
"result": null
}
]
}