cowork-flow 2.3.0 → 2.4.0
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/CHANGELOG.md +18 -1
- package/README.en.md +34 -18
- package/README.md +8 -5
- package/docs/architecture.en.md +95 -0
- package/docs/architecture.md +7 -3
- package/docs/direction.en.md +71 -0
- package/docs/direction.md +6 -1
- package/docs/hosts.en.md +299 -0
- package/docs/hosts.md +3 -1
- package/docs/index.en.md +30 -0
- package/docs/index.md +2 -0
- package/docs/release.en.md +108 -0
- package/docs/release.md +2 -0
- package/package.json +2 -2
- package/presets/claude-code/.claude-plugin/plugin.json +1 -1
- package/presets/claude-code/skills/cowork-flow-bootstrap/SKILL.md +4 -0
- package/presets/codex/.codex-plugin/plugin.json +1 -1
- package/presets/codex/skills/cowork-flow-bootstrap/SKILL.md +4 -0
- package/presets/kimi-code/.kimi-plugin/plugin.json +1 -1
- package/presets/kimi-code/skills/cowork-flow-bootstrap/SKILL.md +4 -0
- package/presets/opencode/cowork-flow/skills/cowork-flow-bootstrap/SKILL.md +4 -0
- package/presets/qoder/.qoder-plugin/plugin.json +1 -1
- package/presets/qoder/skills/cowork-flow-bootstrap/SKILL.md +4 -0
- package/presets/zcode/.zcode-plugin/plugin.json +1 -1
- package/presets/zcode/skills/cowork-flow-bootstrap/SKILL.md +4 -0
- package/src/commands/init.js +129 -2
- package/src/commands/registry.js +3 -1
- package/src/commands/source-refresh.js +5 -1
- package/src/commands/sync.js +3 -0
- package/src/lib/copy-template.js +23 -5
- package/src/lib/host-assets.js +117 -2
- package/src/lib/language.js +162 -0
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/config.yaml +8 -0
- package/template/.cowork-flow/scripts/adapters/cli/task_create_command.py +5 -3
- package/template/.cowork-flow/scripts/adapters/host/host_manifest.py +71 -2
- package/template/.cowork-flow/scripts/infra/config.py +85 -0
- package/template/.cowork-flow/scripts/services/decision_anchor_schema.py +104 -0
- package/template/.cowork-flow/scripts/services/fact_view.py +21 -15
- package/template/.cowork-flow/scripts/services/task_context.py +13 -7
- package/template/.cowork-flow/scripts/services/task_creation.py +72 -30
- package/template/.cowork-flow/scripts/services/task_gate_profiles.py +7 -24
- package/template/.cowork-flow/spec/contracts/context-injection.md +5 -4
- package/template/.cowork-flow/spec/contracts/decision-anchor.md +21 -14
- package/template/.cowork-flow/spec/contracts/plan-binding.md +2 -1
- package/template/.cowork-flow/spec/index.md +26 -26
- package/template/.cowork-flow/spec/references/definition-of-done.md +26 -26
- package/template/.cowork-flow/spec/references/index.md +16 -16
- package/template/.cowork-flow/spec/references/orchestration-patterns.md +71 -71
- package/template/.cowork-flow/spec/references/security-checklist.md +37 -37
- package/template/.cowork-flow/spec/references/testing-checklist.md +32 -32
- package/template/.cowork-flow/spec/runtime/host-assets.json +23 -4
- package/template/.cowork-flow/spec/runtime/index.md +10 -12
- package/template/.cowork-flow/spec/schemas/host-assets.schema.json +31 -0
- package/template/.cowork-flow/spec/schemas/index.md +5 -5
- package/template/.cowork-flow/templates/plan-template.md +91 -0
- package/template/locales/en-US/.cowork-flow/spec/contracts/decision-anchor.md +160 -0
- package/template/locales/en-US/.cowork-flow/templates/plan-template.md +91 -0
- package/template/skills/runtime-health/scripts/doctor.py +110 -0
- package/template/skills/task-planning/SKILL.md +19 -92
|
@@ -6,7 +6,14 @@ from __future__ import annotations
|
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from pathlib import Path
|
|
9
|
+
import re
|
|
9
10
|
|
|
11
|
+
from infra.config import get_language
|
|
12
|
+
from services.decision_anchor_schema import (
|
|
13
|
+
ACCEPTANCE,
|
|
14
|
+
GOAL,
|
|
15
|
+
heading_for,
|
|
16
|
+
)
|
|
10
17
|
from services.task_tree import TaskTreeError, TaskTreeService
|
|
11
18
|
from services import task_graph
|
|
12
19
|
from infra.paths import (
|
|
@@ -19,6 +26,20 @@ from services.task_gate_profiles import GATE_PROFILE_STRICT
|
|
|
19
26
|
from services.task_repository import TaskRepository, TaskRepositoryError
|
|
20
27
|
|
|
21
28
|
|
|
29
|
+
_GOAL_LINE_RE = re.compile(r"^\*\*(?:Goal|目标):\*\*\s*(.+?)\s*$")
|
|
30
|
+
_GOAL_BOLD_COLON_RE = re.compile(r"^\*\*(?:Goal|目标)\*\*:\s*(.+?)\s*$")
|
|
31
|
+
_GOAL_TABLE_RE = re.compile(
|
|
32
|
+
r"^\|\s*\*\*(?:Goal|目标)\*\*\s*\|\s*(.+?)\s*\|\s*$"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
_ANCHOR_PLACEHOLDERS = {
|
|
36
|
+
("zh-CN", GOAL): "<!-- 用一句话描述可观察的目标。 -->",
|
|
37
|
+
("zh-CN", ACCEPTANCE): "<!-- 至少一条,例如:- [ ] AC-001: ... -->",
|
|
38
|
+
("en-US", GOAL): "<!-- One sentence describing the observable outcome. -->",
|
|
39
|
+
("en-US", ACCEPTANCE): "<!-- At least one, e.g. - [ ] AC-001: ... -->",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
22
43
|
class TaskCreationError(RuntimeError):
|
|
23
44
|
"""Raised when task creation cannot be completed."""
|
|
24
45
|
|
|
@@ -66,6 +87,25 @@ class TaskCreationResult:
|
|
|
66
87
|
linked_parent: str | None
|
|
67
88
|
missing_parent: str | None
|
|
68
89
|
generated_anchor: bool
|
|
90
|
+
generated_anchor_from_plan: bool
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _extract_plan_goal(plan_text: str) -> str | None:
|
|
94
|
+
"""First machine-readable goal line, then the legacy table row."""
|
|
95
|
+
for raw in plan_text.splitlines():
|
|
96
|
+
line = raw.strip()
|
|
97
|
+
for pattern in (_GOAL_LINE_RE, _GOAL_BOLD_COLON_RE, _GOAL_TABLE_RE):
|
|
98
|
+
match = pattern.match(line)
|
|
99
|
+
if match:
|
|
100
|
+
return match.group(1).strip()
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _anchor_placeholder(section: str, language: str) -> str:
|
|
105
|
+
return _ANCHOR_PLACEHOLDERS.get(
|
|
106
|
+
(language, section),
|
|
107
|
+
_ANCHOR_PLACEHOLDERS[("zh-CN", section)],
|
|
108
|
+
)
|
|
69
109
|
|
|
70
110
|
|
|
71
111
|
def ensure_tasks_dir(repo_root: Path) -> Path:
|
|
@@ -122,7 +162,7 @@ class TaskCreationService:
|
|
|
122
162
|
created_files.append(task_dir / FILE_TASK_JSON)
|
|
123
163
|
|
|
124
164
|
linked_parent, missing_parent = self._link_parent(request, task_dir)
|
|
125
|
-
generated_anchor = self._generate_anchor(
|
|
165
|
+
generated_anchor, generated_anchor_from_plan = self._generate_anchor(
|
|
126
166
|
task_dir,
|
|
127
167
|
bound_plan_path,
|
|
128
168
|
)
|
|
@@ -136,6 +176,7 @@ class TaskCreationService:
|
|
|
136
176
|
linked_parent=linked_parent,
|
|
137
177
|
missing_parent=missing_parent,
|
|
138
178
|
generated_anchor=generated_anchor,
|
|
179
|
+
generated_anchor_from_plan=generated_anchor_from_plan,
|
|
139
180
|
)
|
|
140
181
|
|
|
141
182
|
def _task_data(
|
|
@@ -316,41 +357,42 @@ class TaskCreationService:
|
|
|
316
357
|
"plan file must live under .cowork-flow/plans",
|
|
317
358
|
)
|
|
318
359
|
|
|
319
|
-
@staticmethod
|
|
320
360
|
def _generate_anchor(
|
|
361
|
+
self,
|
|
321
362
|
task_dir: Path,
|
|
322
363
|
plan_path: Path | None,
|
|
323
|
-
) -> bool:
|
|
324
|
-
|
|
325
|
-
return False
|
|
326
|
-
if not plan_path.is_file():
|
|
327
|
-
return False
|
|
364
|
+
) -> tuple[bool, bool]:
|
|
365
|
+
"""Create a language-specific anchor scaffold.
|
|
328
366
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
"TASK-CREATE-PLAN-001",
|
|
334
|
-
plan_path,
|
|
335
|
-
"plan cannot be read as UTF-8",
|
|
336
|
-
) from error
|
|
337
|
-
|
|
338
|
-
goal = next(
|
|
339
|
-
(
|
|
340
|
-
line.split(":", 1)[1].strip()
|
|
341
|
-
for line in plan_text.splitlines()
|
|
342
|
-
if line.startswith("**Goal:**")
|
|
343
|
-
or line.startswith("**目标:**")
|
|
344
|
-
),
|
|
345
|
-
None,
|
|
346
|
-
)
|
|
367
|
+
A bound plan's goal line (or legacy table row) fills the goal section;
|
|
368
|
+
otherwise the scaffold carries a localized placeholder. An anchor that
|
|
369
|
+
already exists is never overwritten.
|
|
370
|
+
"""
|
|
347
371
|
anchor_file = task_dir / "decision-anchor.md"
|
|
348
|
-
if
|
|
349
|
-
return False
|
|
372
|
+
if anchor_file.exists():
|
|
373
|
+
return False, False
|
|
374
|
+
|
|
375
|
+
goal: str | None = None
|
|
376
|
+
if plan_path is not None and plan_path.is_file():
|
|
377
|
+
try:
|
|
378
|
+
plan_text = plan_path.read_text(encoding="utf-8")
|
|
379
|
+
except (OSError, UnicodeDecodeError) as error:
|
|
380
|
+
raise TaskCreationError(
|
|
381
|
+
"TASK-CREATE-PLAN-001",
|
|
382
|
+
plan_path,
|
|
383
|
+
"plan cannot be read as UTF-8",
|
|
384
|
+
) from error
|
|
385
|
+
goal = _extract_plan_goal(plan_text)
|
|
386
|
+
|
|
387
|
+
language = get_language(self.repo_root)
|
|
388
|
+
goal_heading = heading_for(GOAL, language)
|
|
389
|
+
acceptance_heading = heading_for(ACCEPTANCE, language)
|
|
390
|
+
goal_body = goal or _anchor_placeholder(GOAL, language)
|
|
391
|
+
acceptance_body = _anchor_placeholder(ACCEPTANCE, language)
|
|
350
392
|
try:
|
|
351
393
|
anchor_file.write_text(
|
|
352
|
-
f"##
|
|
353
|
-
"
|
|
394
|
+
f"## {goal_heading}\n\n{goal_body}\n\n"
|
|
395
|
+
f"## {acceptance_heading}\n\n{acceptance_body}\n",
|
|
354
396
|
encoding="utf-8",
|
|
355
397
|
)
|
|
356
398
|
except OSError as error:
|
|
@@ -363,7 +405,7 @@ class TaskCreationService:
|
|
|
363
405
|
anchor_file,
|
|
364
406
|
"decision anchor could not be written",
|
|
365
407
|
) from error
|
|
366
|
-
return True
|
|
408
|
+
return True, goal is not None
|
|
367
409
|
|
|
368
410
|
|
|
369
411
|
def _validate_dev_type(dev_type: str | None, path: Path) -> None:
|
|
@@ -4,7 +4,7 @@ A task created today carries `meta.gateProfile = "strict"`; a task without the
|
|
|
4
4
|
marker keeps the historical gate (legacy), so nothing that already exists is
|
|
5
5
|
retroactively re-gated.
|
|
6
6
|
|
|
7
|
-
The strict gate exists because the old one only checked that the
|
|
7
|
+
The strict gate exists because the old one only checked that the acceptance
|
|
8
8
|
heading was present. An anchor with an empty acceptance section passed, the
|
|
9
9
|
acceptance/evidence gates then found no AC rows to check, and the whole chain
|
|
10
10
|
silently did nothing.
|
|
@@ -12,20 +12,17 @@ silently did nothing.
|
|
|
12
12
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
|
-
import
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
from services.decision_anchor_schema import (
|
|
16
|
+
ACCEPTANCE_RE,
|
|
17
|
+
LIST_ITEM_RE,
|
|
18
|
+
acceptance_section_lines,
|
|
19
|
+
)
|
|
18
20
|
|
|
19
21
|
GATE_PROFILE_STRICT = "strict"
|
|
20
22
|
GATE_PROFILE_LEGACY = "legacy"
|
|
21
23
|
|
|
22
24
|
LIGHT_TASK_TYPE = "tiny"
|
|
23
25
|
|
|
24
|
-
ACCEPTANCE_HEADING = "验收标准"
|
|
25
|
-
|
|
26
|
-
_HEADING_RE = re.compile(r"^##\s*(.+?)\s*$")
|
|
27
|
-
_LIST_ITEM_RE = re.compile(r"^\s*[-*]\s")
|
|
28
|
-
|
|
29
26
|
|
|
30
27
|
def resolve_gate_profile(task_data: dict) -> str:
|
|
31
28
|
"""The gate a task is held to; an unmarked task is legacy."""
|
|
@@ -72,20 +69,6 @@ def is_light_task(task_data: dict) -> bool:
|
|
|
72
69
|
return declares_light_profile(task_data)
|
|
73
70
|
|
|
74
71
|
|
|
75
|
-
def acceptance_section_lines(anchor_text: str) -> list[str]:
|
|
76
|
-
"""Raw lines under `## 验收标准`, up to the next heading."""
|
|
77
|
-
lines: list[str] = []
|
|
78
|
-
inside = False
|
|
79
|
-
for raw in anchor_text.splitlines():
|
|
80
|
-
heading = _HEADING_RE.match(raw.strip())
|
|
81
|
-
if heading:
|
|
82
|
-
inside = heading.group(1) == ACCEPTANCE_HEADING
|
|
83
|
-
continue
|
|
84
|
-
if inside:
|
|
85
|
-
lines.append(raw)
|
|
86
|
-
return lines
|
|
87
|
-
|
|
88
|
-
|
|
89
72
|
def acceptance_row_blockers(anchor_text: str) -> list[str]:
|
|
90
73
|
"""Why the acceptance section cannot start a strict task.
|
|
91
74
|
|
|
@@ -101,7 +84,7 @@ def acceptance_row_blockers(anchor_text: str) -> list[str]:
|
|
|
101
84
|
if match:
|
|
102
85
|
ids.append(match.group(2))
|
|
103
86
|
continue
|
|
104
|
-
if
|
|
87
|
+
if LIST_ITEM_RE.match(raw):
|
|
105
88
|
malformed.append(raw.strip()[:80])
|
|
106
89
|
blockers: list[str] = []
|
|
107
90
|
if not ids:
|
|
@@ -289,7 +289,8 @@ Verify: npm run test:fast; python3 -m pytest tests/ -q
|
|
|
289
289
|
- **Gates**: static preview text, identical on all hosts; the delegated
|
|
290
290
|
variant replaces the self-declaration sentence with "scope is inherited
|
|
291
291
|
from the parent task (read-only reference)".
|
|
292
|
-
- **Verify**: `## 验证命令` lines from
|
|
292
|
+
- **Verify**: `## Verification Commands`/`## 验证命令` lines from
|
|
293
|
+
decision-anchor (first 10, 120 chars
|
|
293
294
|
each) — the agent's own declared self-checks; omitted when none.
|
|
294
295
|
- **Per-edit warning**: PostToolUse on an edit tool injects at most one
|
|
295
296
|
line when the edited file is outside the task's declared scope —
|
|
@@ -326,9 +327,9 @@ Verify: npm run test:fast; python3 -m pytest tests/ -q
|
|
|
326
327
|
budget/limits come from `.cowork-flow/spec/runtime/scope-rules.json`, the
|
|
327
328
|
single source consumed at runtime; a missing or malformed file degrades to
|
|
328
329
|
embedded defaults that are byte-identical with the shipped file (locked by
|
|
329
|
-
`tests/test_scope_rules.py`). The file is
|
|
330
|
-
|
|
331
|
-
it do not survive a sync.
|
|
330
|
+
`tests/test_scope_rules.py`). The file is framework-managed: `cwf project
|
|
331
|
+
sync` refreshes it as part of the synced `spec/runtime/` tree, so local edits
|
|
332
|
+
to it do not survive a sync.
|
|
332
333
|
- Absent for `no_task` / `planning` / `completed` states. Block content is
|
|
333
334
|
byte-identical across host lines for the whole fixture matrix
|
|
334
335
|
(`test/fixtures/stage-contract-matrix.json` drives the equality test:
|
|
@@ -8,8 +8,9 @@ the alternatives", which compresses the number of task artifacts.
|
|
|
8
8
|
|
|
9
9
|
## Schema
|
|
10
10
|
|
|
11
|
-
These section names are
|
|
12
|
-
|
|
11
|
+
These section names are machine-readable. The runtime parser accepts both the
|
|
12
|
+
Chinese and English heading sets, and new anchors use the language configured in
|
|
13
|
+
`.cowork-flow/config.yaml` (`zh-CN` is the default).
|
|
13
14
|
|
|
14
15
|
```markdown
|
|
15
16
|
# Decision Anchor
|
|
@@ -38,14 +39,17 @@ translated heading would simply stop being read.
|
|
|
38
39
|
|
|
39
40
|
## Section requirements
|
|
40
41
|
|
|
42
|
+
Both heading columns below are accepted; the left column is the `zh-CN` output
|
|
43
|
+
and the right column the `en-US` output.
|
|
44
|
+
|
|
41
45
|
| Section | Required | Why |
|
|
42
46
|
|------|------|------|
|
|
43
|
-
| `## 目标` | required | no goal, no acceptance baseline |
|
|
44
|
-
| `## 验收标准` | required | `task_start` is blocked without acceptance criteria |
|
|
45
|
-
| `## 被拒方案` | optional | required for brainstorming tasks, so a rejected option is not reconsidered during execution |
|
|
46
|
-
| `## 关键假设` | optional | filled in for complex tasks to surface implicit constraints; not read by the runtime parser |
|
|
47
|
-
| `## 范围边界` | optional | prevents scope creep |
|
|
48
|
-
| `## 验证命令` | optional | filled in for complex tasks, as the basis for automated verification; when the changed files are covered by `.cowork-flow/spec/backend/` or `frontend/` rules, it must also carry the spec/gate check for the task's `dev_type` (deciding command, or clause-by-clause `pass` / `not_applicable` with reason) |
|
|
47
|
+
| `## 目标` / `## Goal` | required | no goal, no acceptance baseline |
|
|
48
|
+
| `## 验收标准` / `## Acceptance Criteria` | required | `task_start` is blocked without acceptance criteria |
|
|
49
|
+
| `## 被拒方案` / `## Rejected Options` | optional | required for brainstorming tasks, so a rejected option is not reconsidered during execution |
|
|
50
|
+
| `## 关键假设` / `## Key Assumptions` | optional | filled in for complex tasks to surface implicit constraints; not read by the runtime parser |
|
|
51
|
+
| `## 范围边界` / `## Scope Boundary` | optional | prevents scope creep |
|
|
52
|
+
| `## 验证命令` / `## Verification Commands` | optional | filled in for complex tasks, as the basis for automated verification; when the changed files are covered by `.cowork-flow/spec/backend/` or `frontend/` rules, it must also carry the spec/gate check for the task's `dev_type` (deciding command, or clause-by-clause `pass` / `not_applicable` with reason) |
|
|
49
53
|
|
|
50
54
|
### Machine-readable line formats (for injection)
|
|
51
55
|
|
|
@@ -84,15 +88,17 @@ After merging (5 files): `decision-anchor.md` + `implement.jsonl` + `check.jsonl
|
|
|
84
88
|
## Lifecycle check coupling
|
|
85
89
|
|
|
86
90
|
- The preflight for `task next <dir> --run` checks that `decision-anchor.md` is
|
|
87
|
-
non-empty and requires the `## 目标`
|
|
91
|
+
non-empty and requires the `## 目标` / `## Goal` and `## 验收标准` /
|
|
92
|
+
`## Acceptance Criteria` sections to be present.
|
|
88
93
|
- **Gate profile `meta.gateProfile`**: a newly created task is written as
|
|
89
94
|
`"strict"`; an unmarked task is treated as `"legacy"` — existing tasks are not
|
|
90
95
|
retro-fitted with the stricter gate, and the profile is queryable through the
|
|
91
96
|
fact view. On top of the section check, a strict task additionally requires: at
|
|
92
|
-
least one parseable `- [ ] AC-xxx: ...` row in `##
|
|
93
|
-
no non-AC list rows in that
|
|
94
|
-
`task specs` dev-type dispatch
|
|
95
|
-
|
|
97
|
+
least one parseable `- [ ] AC-xxx: ...` row in `## 验收标准` /
|
|
98
|
+
`## Acceptance Criteria`, no duplicate AC ids, no non-AC list rows in that
|
|
99
|
+
section, and a declared `dev_type` (otherwise `task specs` dev-type dispatch
|
|
100
|
+
silently comes back shorter).
|
|
101
|
+
- An acceptance row's checkbox state (`- [ ]` / `- [x]`) and the evidence records
|
|
96
102
|
(the task directory's `evidence.jsonl`) are the fact source of the completion
|
|
97
103
|
gate: completion is blocked when an unchecked AC exists (`LIFECYCLE-AC-001`), a
|
|
98
104
|
declared AC has no evidence (`LIFECYCLE-AC-002`), a strict task cannot read any
|
|
@@ -149,4 +155,5 @@ source; if a task directory has only `prd.md` and no `decision-anchor.md`,
|
|
|
149
155
|
`decision-anchor.md is missing or empty`.
|
|
150
156
|
|
|
151
157
|
An existing legacy task needs a human to convert the `prd.md` content into
|
|
152
|
-
`decision-anchor.md`, fill in `## 目标`
|
|
158
|
+
`decision-anchor.md`, fill in `## 目标` / `## Goal` and `## 验收标准` /
|
|
159
|
+
`## Acceptance Criteria`, and only then start.
|
|
@@ -48,7 +48,8 @@ into `in_progress`:
|
|
|
48
48
|
- `task.json.meta.planFile` exists.
|
|
49
49
|
- `planFile` is a repo-relative `.cowork-flow/plans/` path.
|
|
50
50
|
- The plan file exists and is non-empty.
|
|
51
|
-
- `decision-anchor.md` contains `## 目标` and
|
|
51
|
+
- `decision-anchor.md` contains `## Goal`/`## 目标` and
|
|
52
|
+
`## Acceptance Criteria`/`## 验收标准`.
|
|
52
53
|
- `implement.jsonl` passes the existing context validation.
|
|
53
54
|
|
|
54
55
|
A Tiny task may have no planFile, but must still satisfy the existing anchor and
|
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# Cowork Flow Spec Index
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This directory holds project specs, runtime contracts, and runtime configuration schemas. Layers by responsibility:
|
|
4
4
|
|
|
5
|
-
|
|
|
5
|
+
| Directory | Purpose |
|
|
6
6
|
| --- | --- |
|
|
7
|
-
| `contracts/` |
|
|
8
|
-
| `runtime/` | runtime
|
|
9
|
-
| `schemas/` | runtime
|
|
10
|
-
| `backend/` |
|
|
11
|
-
| `frontend/` |
|
|
12
|
-
| `guides/` | brainstorming/task-planning
|
|
13
|
-
| `references/` |
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
`
|
|
19
|
-
`task-review` skill
|
|
20
|
-
`guides/`
|
|
7
|
+
| `contracts/` | Human-readable contracts for the workflow, host adapters, and subagent protocol. |
|
|
8
|
+
| `runtime/` | Machine configuration read by the runtime, including the contract registry and host asset manifest. |
|
|
9
|
+
| `schemas/` | JSON Schemas for runtime configuration and host contracts. |
|
|
10
|
+
| `backend/` | Backend implementation specs; the review skill reads them on demand and checks each clause. |
|
|
11
|
+
| `frontend/` | Frontend implementation specs; the review skill reads them on demand and checks each clause. |
|
|
12
|
+
| `guides/` | Pre-implementation thinking, cross-layer design, and reuse guidance for brainstorming/task-planning. |
|
|
13
|
+
| `references/` | On-demand reference material (DoD, testing checklist, security checklist, orchestration patterns); never auto-loaded. Load conditions are in the `references` array of contract-registry.json. |
|
|
14
|
+
|
|
15
|
+
Sync ownership: `contracts/`, `runtime/`, `schemas/`, and this file are framework-maintained and follow `cwf project sync`; `backend/`, `frontend/`, `guides/`, and `references/` are project-maintained, and `sync` never overwrites or deletes files there.
|
|
16
|
+
|
|
17
|
+
The workflow kernel only owns machine-checkable facts: task state, file scope, runtime context, and archive consistency.
|
|
18
|
+
Actions, stage guidance, and dedicated runtimes are declared by each Skill's `manifest.json`; there is no centralized Skill registry.
|
|
19
|
+
Natural-language specs under `backend/` and `frontend/` are not registered as runtime gates; the `task-review` skill reads them according to the current diff and task scope and checks each clause.
|
|
20
|
+
`guides/` is pre-implementation clarification and planning reference; selected conclusions belong in `decision-anchor.md` or the task plan.
|
|
21
21
|
|
|
22
22
|
## references/
|
|
23
23
|
|
|
24
|
-
>
|
|
24
|
+
> On-demand reference material. **Never auto-loaded in the main session** — read only when a skill entry or agent judges it necessary.
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
1.
|
|
28
|
-
2.
|
|
29
|
-
3.
|
|
26
|
+
Reference files:
|
|
27
|
+
1. Provide supplemental context for skill entries (the main skill is the entry point; references supplement it).
|
|
28
|
+
2. Reduce what each session must load (narrow-domain specs such as `spec/backend/` are read only when needed).
|
|
29
|
+
3. Provide quick checklists during planning, check, or review.
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
- contract-registry
|
|
33
|
-
- skill
|
|
34
|
-
-
|
|
35
|
-
-
|
|
31
|
+
Loading rules:
|
|
32
|
+
- Read when one of the `loadWhen` conditions in contract-registry matches.
|
|
33
|
+
- Read when a skill body explicitly references a reference ID.
|
|
34
|
+
- Read when the user requests a specific check in the main session.
|
|
35
|
+
- **Never auto-loaded** — that is the difference from `contracts/`.
|
|
@@ -1,44 +1,44 @@
|
|
|
1
1
|
# Definition of Done
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Project-level completion gates. Every change must satisfy these before it is considered "done". They complement per-task ACs; they do not replace them.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## General gates (all tasks)
|
|
6
6
|
|
|
7
|
-
| # |
|
|
7
|
+
| # | Check | Verification |
|
|
8
8
|
|---|---|---|
|
|
9
|
-
| G1 |
|
|
10
|
-
| G2 |
|
|
11
|
-
| G3 |
|
|
12
|
-
| G4 |
|
|
13
|
-
| G5 | Git status snapshot
|
|
9
|
+
| G1 | Implementation satisfies the decision-anchor acceptance criteria | All ACs are verified |
|
|
10
|
+
| G2 | Behavior changes have corresponding tests or an explicit verification command; high-risk tasks cover failure, boundary, or regression paths | `./.cowork-flow/run task next <dir> --validate` and the task verification commands pass |
|
|
11
|
+
| G3 | Check phase is complete with no unresolved blocker | `task-review` verdict is pass, and the completion lifecycle blocker count is 0 |
|
|
12
|
+
| G4 | No newly introduced lint/type/build warnings | lint / build commands pass |
|
|
13
|
+
| G5 | Git status snapshot contains only task-related changes, including staged, unstaged, and untracked | git status --porcelain=v1 -uall |
|
|
14
14
|
|
|
15
|
-
## L0
|
|
15
|
+
## L0 only (docs/format/comments only)
|
|
16
16
|
|
|
17
|
-
| # |
|
|
17
|
+
| # | Check |
|
|
18
18
|
|---|---|
|
|
19
|
-
| L0-1 |
|
|
20
|
-
| L0-2 | git diff --check
|
|
19
|
+
| L0-1 | Change is confirmed non-behavioral (docs/format/comments only) |
|
|
20
|
+
| L0-2 | `git diff --check` reports no whitespace errors |
|
|
21
21
|
|
|
22
|
-
## L1
|
|
22
|
+
## L1 only (single-module behavior change)
|
|
23
23
|
|
|
24
|
-
| # |
|
|
24
|
+
| # | Check |
|
|
25
25
|
|---|---|
|
|
26
|
-
| L1-1 |
|
|
27
|
-
| L1-2 |
|
|
26
|
+
| L1-1 | Brainstorming record exists |
|
|
27
|
+
| L1-2 | Changes do not spread into unrelated modules (git diff range matches task.scope) |
|
|
28
28
|
|
|
29
|
-
## L2
|
|
29
|
+
## L2 only (cross-layer / architecture / migration)
|
|
30
30
|
|
|
31
|
-
| # |
|
|
31
|
+
| # | Check |
|
|
32
32
|
|---|---|
|
|
33
|
-
| L2-1 | proposal.md / spec.md / design.md
|
|
34
|
-
| L2-2 |
|
|
35
|
-
| L2-3 | readiness
|
|
36
|
-
| L2-4 | spec-sync Skill
|
|
33
|
+
| L2-1 | proposal.md / spec.md / design.md are complete |
|
|
34
|
+
| L2-2 | Structured decision review completed per Skill guidance, or explicitly recorded as not applicable |
|
|
35
|
+
| L2-3 | All readiness gates pass (no blocker from `task next <dir> --run`) |
|
|
36
|
+
| L2-4 | spec-sync Skill confirms spec synchronization, or explicitly records that no update is needed |
|
|
37
37
|
|
|
38
|
-
## DoD
|
|
38
|
+
## DoD vs per-task AC
|
|
39
39
|
|
|
40
40
|
| DoD | AC |
|
|
41
41
|
|---|---|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
42
|
+
| Project-level invariant — this task is no exception | Completion conditions specific to the decision-anchor |
|
|
43
|
+
| Source: spec/references/definition-of-done | Source: <task>/decision-anchor.md |
|
|
44
|
+
| Satisfying both = the task is truly complete |
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
# References —
|
|
1
|
+
# References — On-Demand Reference Material
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> **Never auto-loaded.** Read only when a skill entry explicitly references a reference ID, or when an agent judges it necessary.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
1.
|
|
7
|
-
2.
|
|
8
|
-
3.
|
|
5
|
+
This directory holds narrow-scope quick-reference cards that supplement skill entries. Compared with `spec/contracts/` (contracts) and `spec/backend|frontend/` (domain specs), reference files:
|
|
6
|
+
1. Provide quick checklists during check / finish (not full specs).
|
|
7
|
+
2. Provide defensive rule sets for analyzing potential prompt injection.
|
|
8
|
+
3. Declare the collaboration patterns cowork-flow already implements.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
- contract-registry.json
|
|
12
|
-
- skill
|
|
13
|
-
-
|
|
14
|
-
-
|
|
10
|
+
Loading rules:
|
|
11
|
+
- Read when one of `contract-registry.json`'s `references[*].loadWhen` conditions matches.
|
|
12
|
+
- Read when a skill body explicitly references a reference ID.
|
|
13
|
+
- Read when the user requests a specific check in the main session (for example, "security checklist").
|
|
14
|
+
- **Never auto-loaded** — that is the difference from `contracts/`.
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
- [definition-of-done.md](definition-of-done.md) — DoD
|
|
18
|
-
- [testing-checklist.md](testing-checklist.md) —
|
|
19
|
-
- [security-checklist.md](security-checklist.md) — OWASP Top 10
|
|
20
|
-
- [orchestration-patterns.md](orchestration-patterns.md) —
|
|
16
|
+
Current references:
|
|
17
|
+
- [definition-of-done.md](definition-of-done.md) — DoD: project-level completion gates (L0/L1/L2).
|
|
18
|
+
- [testing-checklist.md](testing-checklist.md) — quick reference for test structure, depth, and anti-patterns.
|
|
19
|
+
- [security-checklist.md](security-checklist.md) — OWASP Top 10 mapping plus a quick check.
|
|
20
|
+
- [orchestration-patterns.md](orchestration-patterns.md) — declarative catalog of the collaboration patterns already implemented.
|