cowork-flow 0.0.22 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -55,7 +55,9 @@ cowork-flow 是一个用于新项目初始化协作流程的模板仓库。它
55
55
  项目级协作入口,包含编码前思考、简单优先、外科手术式改动、验证优先等基础原则。接入项目后,应把项目名称、技术栈、运行命令、测试命令和提交策略补齐。
56
56
 
57
57
  `template/.agents/skills/`
58
- 本地技能入口,覆盖 start、before-dev、brainstorming、writing-plans、check、finish-work、continue、meta、python-design、update-spec 和 break-loop 等协作动作。这里的 skill 应保持通用,不承载某个业务项目的一次性细节。
58
+ 本地技能入口,覆盖 start、before-dev、brainstorming、party-mode、writing-plans、check、finish-work、continue、meta、python-design、update-spec 和 break-loop 等协作动作。这里的 skill 应保持通用,不承载某个业务项目的一次性细节。
59
+
60
+ `party-mode` 是用户手动调用的 advisory roundtable。它通过当前 Host Adapter 协调真实子代理讨论,而不是模拟人设;默认 `max_agents=3`、`max_rounds=3`,配置优先级为本次调用、task/change、本地配置、skill 默认值。Party Mode 只产出建议、证据、分歧和验收信号,不能推进任务状态,也不能替代 `cowork-implement` 或 `cowork-check`。
59
61
 
60
62
  `template/.codex/agents/`
61
63
  固定角色 agent 定义,包含 `cowork-research`、`cowork-implement` 和 `cowork-check`,以及对 Codex 默认 `worker`、`default`、`explorer` 的项目级防漂移约束。主会话负责计划与收口,并通过 host adapter 派发固定 agent;正式派发必须先创建 runtime context,再把 `cowork_runtime_context_id` 和 `cowork_host_context_key` 传给子代理。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cowork-flow",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
4
4
  "description": "CLI for installing and maintaining cowork-flow collaboration templates.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: party-mode
3
+ description: Use when the user manually requests Party Mode or a real multi-agent roundtable for advisory discussion, option review, risk review, or decision convergence.
4
+ ---
5
+
6
+ # Party Mode
7
+
8
+ Use this skill as a manual advisory roundtable. Coordinate true child agents, not simulated personas, through the current Host Adapter.
9
+
10
+ ## Boundaries
11
+
12
+ - Party Mode is advisory only.
13
+ - It cannot mutate task status, start/review/complete/archive tasks, add sessions, commit, push, or satisfy formal workflow gates.
14
+ - It cannot satisfy formal Implement or Check completion. Use `cowork-implement` and `cowork-check` for formal phases.
15
+ - Discussion children are leaf executors. They do not dispatch, wait for, list, or close other agents.
16
+ - Generic `worker`, `default`, or `explorer` agents may provide advisory views, but their output never proves implementation or checking done.
17
+
18
+ ## Defaults And Config
19
+
20
+ Built-in defaults:
21
+
22
+ - `max_agents=3`
23
+ - `max_rounds=3`
24
+
25
+ These defaults are configurable values, not hard-coded constants. Effective config order:
26
+
27
+ ```text
28
+ call arguments > task/change config > `.cowork-flow/config.yaml` > skill defaults
29
+ ```
30
+
31
+ Configurable fields:
32
+
33
+ - `max_agents`
34
+ - `max_rounds`
35
+ - agent roster or review lenses
36
+ - report enabled
37
+ - report path
38
+ - whether round 2 or round 3 is allowed
39
+
40
+ Safety gates:
41
+
42
+ - continue conditions can be tightened but not removed
43
+ - stop conditions can be tightened but not removed
44
+ - schema core fields can be extended but not removed
45
+ - exceeding effective limits requires explicit user approval
46
+
47
+ ## Round Model
48
+
49
+ 1. Frame the question, decision needed, scope, and evidence packet.
50
+ 2. Round 1 uses fresh child contexts. Send each child the same packet and one lens. Child agents cannot see each other.
51
+ 3. Synthesize only evidence-backed positions, disagreements, rejected options, and acceptance signals.
52
+ 4. Continue only when a continue condition is met. Send narrow follow-up prompts to the smallest useful set of children.
53
+ 5. Stop when any stop condition is met. Close all live children through the Host Adapter close primitive.
54
+
55
+ Round intent:
56
+
57
+ - Opening round: independent first judgments.
58
+ - Challenge rounds: rebuttal, risk drilldown, or evidence repair on specific disagreements.
59
+ - Convergence rounds: decision check only. Verify, narrow, or choose. Do not open new directions.
60
+
61
+ Default mapping:
62
+
63
+ - Round 1 = Opening.
64
+ - Round 2 = Challenge.
65
+ - Round 3+ = Convergence.
66
+
67
+ Only the user can restart exploration after convergence begins.
68
+
69
+ ## Continue Conditions
70
+
71
+ Run another round only if at least one condition holds:
72
+
73
+ - A disagreement could change the recommended decision.
74
+ - A high risk lacks enough evidence.
75
+ - Acceptance criteria are still not testable.
76
+ - A child found new file, command, rule, or user-scenario evidence.
77
+ - The coordinator cannot write one recommended direction.
78
+
79
+ ## Stop Conditions
80
+
81
+ Stop when any condition holds:
82
+
83
+ - Recommendation, rejected options, and measurable acceptance criteria are clear.
84
+ - Remaining issue is user value preference, not missing evidence.
85
+ - A full round adds no evidence and does not narrow scope.
86
+ - Effective `max_rounds` is reached.
87
+ - Output fails schema, and one repair prompt does not fix it.
88
+
89
+ ## Child Output Schema
90
+
91
+ Each child must return these core fields. Extra fields are allowed only after them.
92
+
93
+ ```text
94
+ position:
95
+ evidence:
96
+ risk:
97
+ tradeoff:
98
+ rejected_option:
99
+ acceptance_signal:
100
+ what_would_change_my_mind:
101
+ ```
102
+
103
+ Reject unsupported opinion. Evidence should name files, commands, rules, observed behavior, user scenarios, or concrete assumptions.
104
+
105
+ ## Coordinator Output Schema
106
+
107
+ Final synthesis must return these core fields. Extra fields are allowed only after them.
108
+
109
+ ```text
110
+ consensus:
111
+ disagreements:
112
+ evidence:
113
+ decision:
114
+ rejected_options:
115
+ acceptance_criteria:
116
+ open_questions:
117
+ stop_reason:
118
+ ```
119
+
120
+ Keep the final decision traceable to child evidence. Do not count votes as validation.
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: party-mode
3
+ description: Use when the user manually requests Party Mode or a real multi-agent roundtable for advisory discussion, option review, risk review, or decision convergence.
4
+ ---
5
+
6
+ # Party Mode
7
+
8
+ Use this skill as a manual advisory roundtable. Coordinate true child agents, not simulated personas, through the current Host Adapter.
9
+
10
+ ## Boundaries
11
+
12
+ - Party Mode is advisory only.
13
+ - It cannot mutate task status, start/review/complete/archive tasks, add sessions, commit, push, or satisfy formal workflow gates.
14
+ - It cannot satisfy formal Implement or Check completion. Use `cowork-implement` and `cowork-check` for formal phases.
15
+ - Discussion children are leaf executors. They do not dispatch, wait for, list, or close other agents.
16
+ - Generic `worker`, `default`, or `explorer` agents may provide advisory views, but their output never proves implementation or checking done.
17
+
18
+ ## Defaults And Config
19
+
20
+ Built-in defaults:
21
+
22
+ - `max_agents=3`
23
+ - `max_rounds=3`
24
+
25
+ These defaults are configurable values, not hard-coded constants. Effective config order:
26
+
27
+ ```text
28
+ call arguments > task/change config > `.cowork-flow/config.yaml` > skill defaults
29
+ ```
30
+
31
+ Configurable fields:
32
+
33
+ - `max_agents`
34
+ - `max_rounds`
35
+ - agent roster or review lenses
36
+ - report enabled
37
+ - report path
38
+ - whether round 2 or round 3 is allowed
39
+
40
+ Safety gates:
41
+
42
+ - continue conditions can be tightened but not removed
43
+ - stop conditions can be tightened but not removed
44
+ - schema core fields can be extended but not removed
45
+ - exceeding effective limits requires explicit user approval
46
+
47
+ ## Round Model
48
+
49
+ 1. Frame the question, decision needed, scope, and evidence packet.
50
+ 2. Round 1 uses fresh child contexts. Send each child the same packet and one lens. Child agents cannot see each other.
51
+ 3. Synthesize only evidence-backed positions, disagreements, rejected options, and acceptance signals.
52
+ 4. Continue only when a continue condition is met. Send narrow follow-up prompts to the smallest useful set of children.
53
+ 5. Stop when any stop condition is met. Close all live children through the Host Adapter close primitive.
54
+
55
+ Round intent:
56
+
57
+ - Opening round: independent first judgments.
58
+ - Challenge rounds: rebuttal, risk drilldown, or evidence repair on specific disagreements.
59
+ - Convergence rounds: decision check only. Verify, narrow, or choose. Do not open new directions.
60
+
61
+ Default mapping:
62
+
63
+ - Round 1 = Opening.
64
+ - Round 2 = Challenge.
65
+ - Round 3+ = Convergence.
66
+
67
+ Only the user can restart exploration after convergence begins.
68
+
69
+ ## Continue Conditions
70
+
71
+ Run another round only if at least one condition holds:
72
+
73
+ - A disagreement could change the recommended decision.
74
+ - A high risk lacks enough evidence.
75
+ - Acceptance criteria are still not testable.
76
+ - A child found new file, command, rule, or user-scenario evidence.
77
+ - The coordinator cannot write one recommended direction.
78
+
79
+ ## Stop Conditions
80
+
81
+ Stop when any condition holds:
82
+
83
+ - Recommendation, rejected options, and measurable acceptance criteria are clear.
84
+ - Remaining issue is user value preference, not missing evidence.
85
+ - A full round adds no evidence and does not narrow scope.
86
+ - Effective `max_rounds` is reached.
87
+ - Output fails schema, and one repair prompt does not fix it.
88
+
89
+ ## Child Output Schema
90
+
91
+ Each child must return these core fields. Extra fields are allowed only after them.
92
+
93
+ ```text
94
+ position:
95
+ evidence:
96
+ risk:
97
+ tradeoff:
98
+ rejected_option:
99
+ acceptance_signal:
100
+ what_would_change_my_mind:
101
+ ```
102
+
103
+ Reject unsupported opinion. Evidence should name files, commands, rules, observed behavior, user scenarios, or concrete assumptions.
104
+
105
+ ## Coordinator Output Schema
106
+
107
+ Final synthesis must return these core fields. Extra fields are allowed only after them.
108
+
109
+ ```text
110
+ consensus:
111
+ disagreements:
112
+ evidence:
113
+ decision:
114
+ rejected_options:
115
+ acceptance_criteria:
116
+ open_questions:
117
+ stop_reason:
118
+ ```
119
+
120
+ Keep the final decision traceable to child evidence. Do not count votes as validation.
@@ -1 +1 @@
1
- 0.0.22
1
+ 0.0.24
@@ -9,6 +9,7 @@ import re
9
9
  import sys
10
10
  from datetime import datetime
11
11
  from pathlib import Path
12
+ from typing import Iterable
12
13
 
13
14
  from common.archive_utils import archive_directory_resumable
14
15
  from common.paths import (
@@ -161,6 +162,63 @@ def _normalize_archive_metadata(repo_root: Path, change_dir: Path) -> None:
161
162
  _write_metadata(change_dir, metadata)
162
163
 
163
164
 
165
+ def _same_path(left: Path, right: Path) -> bool:
166
+ try:
167
+ return left.resolve() == right.resolve()
168
+ except OSError:
169
+ return left.absolute() == right.absolute()
170
+
171
+
172
+ def _task_link_matches(repo_root: Path, value: object, task_paths: Iterable[Path]) -> bool:
173
+ resolved = _resolve_link(repo_root, "tasks", value)
174
+ if resolved is None:
175
+ return False
176
+ return any(_same_path(resolved, task_path) for task_path in task_paths)
177
+
178
+
179
+ def linked_active_changes_for_task(repo_root: Path, task_paths: Iterable[Path]) -> list[str]:
180
+ """Return active change slugs whose metadata points at one of the task paths."""
181
+ changes_dir = _changes_dir(repo_root)
182
+ if not changes_dir.is_dir():
183
+ return []
184
+
185
+ paths = tuple(task_paths)
186
+ slugs: list[str] = []
187
+ for change_dir in sorted(changes_dir.iterdir()):
188
+ if not change_dir.is_dir() or change_dir.name == DIR_ARCHIVE:
189
+ continue
190
+ metadata = _read_metadata(change_dir)
191
+ if metadata.get("status") == "archived":
192
+ continue
193
+ if _task_link_matches(repo_root, metadata.get("task"), paths):
194
+ slugs.append(change_dir.name)
195
+ return slugs
196
+
197
+
198
+ def archive_change_by_slug(repo_root: Path, slug: str) -> Path | None:
199
+ source = _change_dir(repo_root, slug)
200
+ if source.is_dir():
201
+ _normalize_archive_metadata(repo_root, source)
202
+
203
+ if not validate_change(repo_root, slug, quiet=True):
204
+ return None
205
+
206
+ month = datetime.now().astimezone().strftime("%Y-%m")
207
+ destination = _archive_dir(repo_root) / month / slug
208
+ result = archive_directory_resumable(source, destination)
209
+ if not result.ok:
210
+ level = "Warning" if result.partial else "Error"
211
+ print(f"{level}: {result.message}", file=sys.stderr)
212
+ return None
213
+
214
+ metadata = _read_metadata(destination)
215
+ metadata["status"] = "archived"
216
+ metadata["archived_at"] = _now_iso()
217
+ metadata["task"] = _normalize_task_link(repo_root, metadata.get("task"))
218
+ _write_metadata(destination, metadata)
219
+ return destination
220
+
221
+
164
222
 
165
223
  def _display_path(repo_root: Path, path: Path) -> str:
166
224
  try:
@@ -272,27 +330,9 @@ def validate_command(args: argparse.Namespace) -> int:
272
330
  def archive_change(args: argparse.Namespace) -> int:
273
331
  repo_root = get_repo_root()
274
332
  slug = args.slug
275
- source = _change_dir(repo_root, slug)
276
- if source.is_dir():
277
- _normalize_archive_metadata(repo_root, source)
278
-
279
- if not validate_change(repo_root, slug, quiet=True):
333
+ if archive_change_by_slug(repo_root, slug) is None:
280
334
  return 1
281
335
 
282
- month = datetime.now().astimezone().strftime("%Y-%m")
283
- destination = _archive_dir(repo_root) / month / slug
284
- result = archive_directory_resumable(source, destination)
285
- if not result.ok:
286
- level = "Warning" if result.partial else "Error"
287
- print(f"{level}: {result.message}", file=sys.stderr)
288
- return 1
289
-
290
- metadata = _read_metadata(destination)
291
- metadata["status"] = "archived"
292
- metadata["archived_at"] = _now_iso()
293
- metadata["task"] = _normalize_task_link(repo_root, metadata.get("task"))
294
- _write_metadata(destination, metadata)
295
-
296
336
  print(f"archived {slug}")
297
337
  return 0
298
338
 
@@ -14,7 +14,7 @@ Usage:
14
14
  ./.cowork-flow/run task complete [dir] # Mark task completed
15
15
  ./.cowork-flow/run task current # Show active session task
16
16
  ./.cowork-flow/run task finish # Clear active session task
17
- ./.cowork-flow/run task archive <task-name> # Archive completed task
17
+ ./.cowork-flow/run task archive <task-name> # Archive completed task and linked changes
18
18
  ./.cowork-flow/run task list # List active tasks
19
19
  ./.cowork-flow/run task list-archive [month] # List archived tasks
20
20
  ./.cowork-flow/run task add-subtask <parent-dir> <child-dir> # Link child to parent
@@ -47,6 +47,7 @@ from common.active_task import (
47
47
  from common.paths import (
48
48
  DIR_WORKFLOW,
49
49
  DIR_AGENTS,
50
+ DIR_CHANGES,
50
51
  DIR_TASKS,
51
52
  DIR_SPEC,
52
53
  DIR_ARCHIVE,
@@ -1120,6 +1121,40 @@ def _print_blockers(blockers: list[str]) -> None:
1120
1121
  print(f" - {blocker}")
1121
1122
 
1122
1123
 
1124
+ def _linked_active_changes_for_task(repo_root: Path, task_dir: Path) -> list[str]:
1125
+ from change import linked_active_changes_for_task
1126
+
1127
+ return linked_active_changes_for_task(repo_root, (task_dir,))
1128
+
1129
+
1130
+ def _linked_changes_ready_for_archive(repo_root: Path, slugs: list[str]) -> bool:
1131
+ from change import validate_change
1132
+
1133
+ ready = True
1134
+ for slug in slugs:
1135
+ if not validate_change(repo_root, slug, quiet=True):
1136
+ print(
1137
+ colored(f"Error: Linked change is not ready to archive: {slug}", Colors.RED),
1138
+ file=sys.stderr,
1139
+ )
1140
+ ready = False
1141
+ return ready
1142
+
1143
+
1144
+ def _archive_linked_changes(repo_root: Path, slugs: list[str]) -> bool:
1145
+ from change import archive_change_by_slug
1146
+
1147
+ for slug in slugs:
1148
+ if archive_change_by_slug(repo_root, slug) is None:
1149
+ print(
1150
+ colored(f"Error: Failed to archive linked change: {slug}", Colors.RED),
1151
+ file=sys.stderr,
1152
+ )
1153
+ return False
1154
+ print(colored(f"Archived linked change: {slug}", Colors.GREEN), file=sys.stderr)
1155
+ return True
1156
+
1157
+
1123
1158
  def cmd_next(args: argparse.Namespace) -> int:
1124
1159
  """Print the next safe workflow action without mutating state."""
1125
1160
  repo_root = get_repo_root()
@@ -1216,7 +1251,10 @@ def cmd_next(args: argparse.Namespace) -> int:
1216
1251
  if status in DONE_STATUSES:
1217
1252
  print("Next action: finalize, commit, archive, and record session")
1218
1253
  print("Command: git status --short")
1254
+ linked_changes = _linked_active_changes_for_task(repo_root, task_dir)
1219
1255
  print(f"Then: ./.cowork-flow/run task archive {Path(task_path).name}")
1256
+ for slug in linked_changes:
1257
+ print(f"Then: ./.cowork-flow/run change archive {slug} (handled by task archive)")
1220
1258
  _print_blockers(blockers)
1221
1259
  return 0
1222
1260
 
@@ -1231,7 +1269,7 @@ def cmd_next(args: argparse.Namespace) -> int:
1231
1269
  # =============================================================================
1232
1270
 
1233
1271
  def cmd_archive(args: argparse.Namespace) -> int:
1234
- """Archive completed task."""
1272
+ """Archive completed task and linked changes."""
1235
1273
  repo_root = get_repo_root()
1236
1274
  task_name = args.name
1237
1275
 
@@ -1258,6 +1296,10 @@ def cmd_archive(args: argparse.Namespace) -> int:
1258
1296
  if task_json_path.is_file():
1259
1297
  task_data = _read_json_file(task_json_path)
1260
1298
 
1299
+ linked_changes = _linked_active_changes_for_task(repo_root, task_dir)
1300
+ if linked_changes and not _linked_changes_ready_for_archive(repo_root, linked_changes):
1301
+ return 1
1302
+
1261
1303
  # Archive
1262
1304
  result = archive_task_complete(task_dir, repo_root)
1263
1305
  if "archived_to" not in result:
@@ -1284,6 +1326,9 @@ def cmd_archive(args: argparse.Namespace) -> int:
1284
1326
  year_month = archive_dest.parent.name
1285
1327
  print(colored(f"Archived: {dir_name} -> archive/{year_month}/", Colors.GREEN), file=sys.stderr)
1286
1328
 
1329
+ if linked_changes and not _archive_linked_changes(repo_root, linked_changes):
1330
+ return 1
1331
+
1287
1332
  # Auto-commit only when explicitly requested.
1288
1333
  if getattr(args, "commit", False) and not getattr(args, "no_commit", False):
1289
1334
  _auto_commit_archive(dir_name, repo_root)
@@ -1297,13 +1342,19 @@ def cmd_archive(args: argparse.Namespace) -> int:
1297
1342
 
1298
1343
 
1299
1344
  def _auto_commit_archive(task_name: str, repo_root: Path) -> None:
1300
- """Stage .cowork-flow/tasks/ changes and commit after archive."""
1345
+ """Stage task/change archive changes and commit after archive."""
1301
1346
  tasks_rel = f"{DIR_WORKFLOW}/{DIR_TASKS}"
1302
- _run_git_command(["add", "-A", tasks_rel], cwd=repo_root)
1347
+ changes_rel = f"{DIR_WORKFLOW}/{DIR_CHANGES}"
1348
+ archive_rels = [
1349
+ rel
1350
+ for rel in (tasks_rel, changes_rel)
1351
+ if (repo_root / rel).exists()
1352
+ ]
1353
+ _run_git_command(["add", "-A", *archive_rels], cwd=repo_root)
1303
1354
 
1304
1355
  # Check if there are staged changes
1305
1356
  rc, _, _ = _run_git_command(
1306
- ["diff", "--cached", "--quiet", "--", tasks_rel], cwd=repo_root
1357
+ ["diff", "--cached", "--quiet", "--", *archive_rels], cwd=repo_root
1307
1358
  )
1308
1359
  if rc == 0:
1309
1360
  print("[OK] No task changes to commit.", file=sys.stderr)
@@ -1564,7 +1615,7 @@ Usage:
1564
1615
  ./.cowork-flow/run task complete [dir] Mark task completed
1565
1616
  ./.cowork-flow/run task finish Clear active session task
1566
1617
  ./.cowork-flow/run task next [dir] Show next safe workflow action
1567
- ./.cowork-flow/run task archive <task-name> Archive completed task
1618
+ ./.cowork-flow/run task archive <task-name> Archive completed task and linked changes
1568
1619
  ./.cowork-flow/run task add-subtask <parent> <child> Link child task to parent
1569
1620
  ./.cowork-flow/run task remove-subtask <parent> <child> Unlink child from parent
1570
1621
  ./.cowork-flow/run task list [--mine] [--status <status>] List tasks
@@ -12,6 +12,12 @@ classification or a prompt handshake.
12
12
  - Generic `worker`, `default`, or `explorer` dispatch is advisory only and
13
13
  cannot satisfy formal Implement or Check completion.
14
14
 
15
+ ## Advisory Party Mode
16
+
17
+ Party Mode discussion children are advisory leaf executors. They use fresh child contexts for evidence gathering, disagreement surfacing, risk review, and acceptance-signal review. They cannot mutate task status, write code, archive, commit, or coordinate other agents. Their output cannot satisfy formal Implement or Check completion.
18
+
19
+ The `party-mode` skill owns round limits, continuation gates, stop gates, and output schemas. This document remains the formal `cowork-*` dispatch protocol source.
20
+
15
21
  ## Runtime Context
16
22
 
17
23
  Before spawning a formal child, the main session creates:
@@ -92,27 +92,33 @@ changes -> brainstorming -> read spec -> plan -> tasks -> implement -> check ->
92
92
  - 固定 `cowork-*` 代理是叶子执行者;不得再派发、等待、列出或取消其他代理。
93
93
  - 通用 `worker`、`default` 或 `explorer` 只能作为 advisory work,不能满足正式实现或检查完成条件。
94
94
 
95
- ## 3.2 并行会话
95
+ ## 3.2 手动 Party Mode
96
+
97
+ Party Mode 是用户手动触发的 advisory roundtable。主会话可通过当前宿主适配器创建 fresh child contexts,收集真实讨论子代理的证据、分歧、风险和可测验收信号,再由主会话综合结论。
98
+
99
+ Party Mode 不能推进任务状态,不能满足正式实现或检查完成条件,也不能替代 `cowork-implement` 或 `cowork-check`。轮次上限、继续/停止条件、输出 schema 和可配置默认值由 party-mode skill 定义;正式子代理协议仍以 `.cowork-flow/spec/subagent-dispatch.md` 为准。
100
+
101
+ ## 3.3 并行会话
96
102
 
97
103
  并行执行采用干净隔离的并行会话模型。并行只是执行策略,不改变固定代理叶子边界。
98
104
 
99
- ### 3.2.1 并行决策
105
+ ### 3.3.1 并行决策
100
106
 
101
107
  - 用户无需在需求输入时声明是否并行;计划阶段由主会话评估并行可行性。
102
108
  - 开发计划必须明确执行策略:串行执行,或列出可并行的低冲突切片。
103
109
  - 同一文件、同一行为链、依赖未合并或验收标准不清的工作不得并行,改为串行。
104
110
 
105
- ### 3.2.2 隔离方式
111
+ ### 3.3.2 隔离方式
106
112
 
107
113
  - 多个独立任务优先拆成多个 cowork-flow 会话。
108
114
  - 只要存在写入冲突风险,就用独立 `git worktree` 隔离。
109
115
 
110
- ### 3.2.3 单任务内切片
116
+ ### 3.3.3 单任务内切片
111
117
 
112
118
  - 单个任务内只允许低冲突切片并行。
113
119
  - 每个切片必须写清文件归属、依赖关系、预期产物和验证命令。
114
120
 
115
- ### 3.2.4 协调与验收
121
+ ### 3.3.4 协调与验收
116
122
 
117
123
  - 主会话是唯一协调者:派发所有子代理后逐个等待,核对子代理汇报的文件、命令和产物,再用适配器列表/取消原语收口。
118
124
  - 多个实现切片合并后必须再执行最终集成验证;不能把各子代理的局部通过当成整体通过。
@@ -214,6 +220,8 @@ L2 任务在 `task start` 前必须通过 readiness gate;同一 blocker 列表
214
220
  git add <expected files>
215
221
  git commit -m "<message>"
216
222
  ```
223
+ `task archive <task-name>` 会归档 task,并自动归档 `change.yaml.task`
224
+ 指向该 task 的 active change;无法通过 `change validate` 的 change 不会被自动归档。
217
225
 
218
226
  ## 9. 恢复规则
219
227