cowork-flow 0.0.37 → 0.0.39
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 +27 -14
- package/package.json +1 -1
- package/src/commands/init.js +39 -28
- package/src/commands/sync.js +2 -2
- package/src/lib/asset-plan.js +127 -0
- package/src/lib/copy-template.js +101 -141
- package/src/lib/host-assets.js +231 -0
- package/src/lib/plan-applier.js +329 -0
- package/src/lib/platforms.js +15 -76
- package/src/lib/skill-registry.js +503 -0
- package/template/.claude/agents/cowork-check.md +10 -1
- package/template/.claude/agents/cowork-implement.md +11 -2
- package/template/.claude/hooks/inject-workflow-state.py +51 -254
- package/template/.codex/agents/cowork-check.toml +12 -3
- package/template/.codex/agents/cowork-implement.toml +11 -2
- package/template/.codex/agents/default.toml +3 -2
- package/template/.codex/agents/explorer.toml +3 -2
- package/template/.codex/agents/worker.toml +2 -1
- package/template/.codex/hooks/inject-workflow-state.py +46 -265
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/scripts/application/__init__.py +1 -0
- package/template/.cowork-flow/scripts/application/batch_execution.py +743 -0
- package/template/.cowork-flow/scripts/application/runtime_context_service.py +365 -0
- package/template/.cowork-flow/scripts/application/task_archive.py +220 -0
- package/template/.cowork-flow/scripts/application/task_context.py +765 -0
- package/template/.cowork-flow/scripts/application/task_creation.py +201 -0
- package/template/.cowork-flow/scripts/application/task_lifecycle.py +532 -0
- package/template/.cowork-flow/scripts/application/task_tree.py +179 -0
- package/template/.cowork-flow/scripts/commands/doctor.py +78 -57
- package/template/.cowork-flow/scripts/commands/party_mode_v2.py +671 -425
- package/template/.cowork-flow/scripts/commands/subagent.py +38 -26
- package/template/.cowork-flow/scripts/commands/task.py +535 -1953
- package/template/.cowork-flow/scripts/commands/task_archive_commands.py +195 -0
- package/template/.cowork-flow/scripts/commands/task_context_commands.py +240 -0
- package/template/.cowork-flow/scripts/commands/task_create_command.py +164 -0
- package/template/.cowork-flow/scripts/commands/task_navigation.py +407 -0
- package/template/.cowork-flow/scripts/commands/task_parser.py +364 -0
- package/template/.cowork-flow/scripts/commands/task_support.py +76 -0
- package/template/.cowork-flow/scripts/commands/task_tree_commands.py +160 -0
- package/template/.cowork-flow/scripts/common/core/execution_context.py +161 -85
- package/template/.cowork-flow/scripts/common/core/host_manifest.py +393 -0
- package/template/.cowork-flow/scripts/common/core/skill_registry.py +568 -0
- package/template/.cowork-flow/scripts/common/gates/coding_standards.py +58 -7
- package/template/.cowork-flow/scripts/common/gates/gates.py +323 -46
- package/template/.cowork-flow/scripts/common/gates/models.py +196 -0
- package/template/.cowork-flow/scripts/common/gates/registry.py +79 -0
- package/template/.cowork-flow/scripts/common/gates/tdd_evidence.py +13 -13
- package/template/.cowork-flow/scripts/common/gates/validate_coding_standards.py +104 -62
- package/template/.cowork-flow/scripts/common/gates/validate_implementation.py +39 -22
- package/template/.cowork-flow/scripts/common/gates/validate_rules.py +223 -40
- package/template/.cowork-flow/scripts/common/git/git_context.py +216 -182
- package/template/.cowork-flow/scripts/common/host/__init__.py +1 -0
- package/template/.cowork-flow/scripts/common/host/workflow_state_hook.py +303 -0
- package/template/.cowork-flow/scripts/common/storage/__init__.py +1 -0
- package/template/.cowork-flow/scripts/common/storage/operation_log.py +72 -0
- package/template/.cowork-flow/scripts/common/storage/state_store.py +279 -0
- package/template/.cowork-flow/scripts/common/storage/unit_of_work.py +214 -0
- package/template/.cowork-flow/scripts/common/task/active_task.py +93 -135
- package/template/.cowork-flow/scripts/common/task/batch_mode.py +33 -120
- package/template/.cowork-flow/scripts/common/task/decision_review.py +85 -0
- package/template/.cowork-flow/scripts/common/task/readiness.py +9 -15
- package/template/.cowork-flow/scripts/common/task/task_repository.py +156 -0
- package/template/.cowork-flow/scripts/run.py +24 -0
- package/template/.cowork-flow/spec/contracts/decision-anchor.md +8 -2
- package/template/.cowork-flow/spec/contracts/subagent-dispatch.md +2 -4
- package/template/.cowork-flow/spec/contracts/workflow-state-templates.md +1 -1
- package/template/.cowork-flow/spec/protocols/decision-review.md +28 -0
- package/template/.cowork-flow/spec/protocols/review.md +34 -0
- package/template/.cowork-flow/spec/protocols/spec-maintenance.md +16 -0
- package/template/.cowork-flow/spec/protocols/tdd.md +30 -0
- package/template/.cowork-flow/spec/references/definition-of-done.md +4 -4
- package/template/.cowork-flow/spec/references/orchestration-patterns.md +1 -1
- package/template/.cowork-flow/spec/runtime/contract-registry.json +25 -0
- package/template/.cowork-flow/spec/runtime/host-assets.json +214 -0
- package/template/.cowork-flow/spec/runtime/index.md +8 -0
- package/template/.cowork-flow/spec/runtime/rules.json +61 -10
- package/template/.cowork-flow/spec/runtime/skill-registry.json +397 -0
- package/template/.cowork-flow/spec/schemas/host-assets.schema.json +173 -0
- package/template/.cowork-flow/spec/schemas/rules.schema.json +10 -1
- package/template/.cowork-flow/spec/schemas/skill-registry.schema.json +202 -0
- package/template/.cowork-flow/workflow.md +18 -13
- package/template/.opencode/agents/cowork-check.md +11 -0
- package/template/.opencode/agents/cowork-implement.md +16 -1
- package/template/.zcode/.zcode-plugin/plugin.json +1 -1
- package/template/.zcode/hooks/inject-context.js +3 -85
- package/template/.zcode/hooks/inject-context.selfcheck.mjs +6 -6
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/decision-anchor.md +8 -2
- package/template/.zcode/scaffold/.cowork-flow/spec/contracts/subagent-dispatch.md +2 -4
- package/template/.zcode/scaffold/.cowork-flow/spec/runtime/rules.json +61 -10
- package/template/.zcode/scaffold/.cowork-flow/spec/schemas/rules.schema.json +10 -1
- package/template/.zcode/scaffold/.cowork-flow/workflow.md +18 -13
- package/template/.zcode/scaffold/AGENTS.md +18 -8
- package/template/AGENTS.md +1 -1
- package/template/skills/batch-mode/SKILL.md +140 -76
- package/template/skills/brainstorming/SKILL.md +2 -2
- package/template/skills/cowork-flow/SKILL.md +42 -0
- package/template/skills/party-mode/SHARED-BOUNDARIES.md +1 -1
- package/template/skills/party-mode/SKILL.md +48 -119
- package/template/.cowork-flow/scripts/common/gates/spec_validator.py +0 -53
- package/template/.cowork-flow/scripts/common/gates/validate_jsonl.py +0 -32
- package/template/skills/before-dev/SKILL.md +0 -41
- package/template/skills/check/SKILL.md +0 -53
- package/template/skills/check/simplification-guide.md +0 -47
- package/template/skills/continue/SKILL.md +0 -29
- package/template/skills/doubt-review/SKILL.md +0 -118
- package/template/skills/finish-work/SKILL.md +0 -32
- package/template/skills/party-mode-v2/SKILL.md +0 -75
- package/template/skills/start/SKILL.md +0 -78
- package/template/skills/tdd/SKILL.md +0 -74
- package/template/skills/update-spec/SKILL.md +0 -39
- package/template/skills/using-cowork-flow/SKILL.md +0 -80
|
@@ -3,34 +3,31 @@
|
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
|
-
import hashlib
|
|
7
6
|
import json
|
|
8
7
|
import os
|
|
9
|
-
import re
|
|
10
8
|
import sys
|
|
11
9
|
from pathlib import Path
|
|
12
10
|
from typing import Any
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
12
|
+
|
|
13
|
+
def _read_input() -> dict[str, Any]:
|
|
14
|
+
raw = sys.stdin.buffer.read()
|
|
15
|
+
if not raw.strip():
|
|
16
|
+
return {}
|
|
17
|
+
try:
|
|
18
|
+
data = json.loads(raw.decode("utf-8-sig"))
|
|
19
|
+
except (UnicodeDecodeError, json.JSONDecodeError, ValueError):
|
|
20
|
+
return {}
|
|
21
|
+
if not isinstance(data, dict):
|
|
22
|
+
return {}
|
|
23
|
+
if "claude_session_id" not in data:
|
|
24
|
+
session_id = data.get("session_id")
|
|
25
|
+
if isinstance(session_id, str) and session_id.strip():
|
|
26
|
+
data["claude_session_id"] = session_id
|
|
27
|
+
return data
|
|
31
28
|
|
|
32
29
|
|
|
33
|
-
def
|
|
30
|
+
def _find_root(start: Path) -> Path | None:
|
|
34
31
|
current = start.resolve()
|
|
35
32
|
while True:
|
|
36
33
|
if (current / ".cowork-flow").is_dir():
|
|
@@ -40,250 +37,50 @@ def _find_repo_root(start: Path) -> Path | None:
|
|
|
40
37
|
current = current.parent
|
|
41
38
|
|
|
42
39
|
|
|
43
|
-
def _read_hook_input() -> dict[str, Any]:
|
|
44
|
-
try:
|
|
45
|
-
raw = sys.stdin.buffer.read()
|
|
46
|
-
except AttributeError:
|
|
47
|
-
text = sys.stdin.read()
|
|
48
|
-
else:
|
|
49
|
-
if not raw.strip():
|
|
50
|
-
return {}
|
|
51
|
-
try:
|
|
52
|
-
text = raw.decode("utf-8-sig")
|
|
53
|
-
except UnicodeDecodeError:
|
|
54
|
-
encoding = getattr(sys.stdin, "encoding", None) or "utf-8"
|
|
55
|
-
text = raw.decode(encoding, errors="replace")
|
|
56
|
-
if not text.strip():
|
|
57
|
-
return {}
|
|
58
|
-
try:
|
|
59
|
-
data = json.loads(text)
|
|
60
|
-
except (json.JSONDecodeError, ValueError):
|
|
61
|
-
return {}
|
|
62
|
-
return data if isinstance(data, dict) else {}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def _hook_event_name(hook_input: dict[str, Any]) -> str:
|
|
66
|
-
value = hook_input.get("hook_event_name") or hook_input.get("hookEventName")
|
|
67
|
-
if isinstance(value, str) and value.strip():
|
|
68
|
-
return value.strip()
|
|
69
|
-
return "UserPromptSubmit"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def _normalize_hook_input(hook_input: dict[str, Any]) -> dict[str, Any]:
|
|
73
|
-
normalized = dict(hook_input)
|
|
74
|
-
if "claude_session_id" not in normalized:
|
|
75
|
-
session_id = normalized.get("session_id")
|
|
76
|
-
if isinstance(session_id, str) and session_id.strip():
|
|
77
|
-
normalized["claude_session_id"] = session_id
|
|
78
|
-
return normalized
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def _load_breadcrumbs(root: Path) -> dict[str, str]:
|
|
82
|
-
workflow = root / ".cowork-flow" / "spec" / "contracts" / "workflow-state-templates.md"
|
|
83
|
-
try:
|
|
84
|
-
text = workflow.read_text(encoding="utf-8")
|
|
85
|
-
except OSError:
|
|
86
|
-
return {}
|
|
87
|
-
return {match.group(1): match.group(2).strip() for match in TAG_RE.finditer(text)}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def _as_string_list(value: Any) -> list[str]:
|
|
91
|
-
if not isinstance(value, list):
|
|
92
|
-
return []
|
|
93
|
-
return [item for item in value if isinstance(item, str) and item.strip()]
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def _load_contract_registry(root: Path) -> tuple[list[dict[str, Any]], str | None]:
|
|
97
|
-
registry_file = root / ".cowork-flow" / "spec" / "runtime" / "contract-registry.json"
|
|
98
|
-
try:
|
|
99
|
-
data = json.loads(registry_file.read_text(encoding="utf-8"))
|
|
100
|
-
except OSError:
|
|
101
|
-
data = DEFAULT_CONTRACT_REGISTRY
|
|
102
|
-
warning = f"contract registry unavailable at {registry_file}; using fallback digest"
|
|
103
|
-
except json.JSONDecodeError:
|
|
104
|
-
data = DEFAULT_CONTRACT_REGISTRY
|
|
105
|
-
warning = f"contract registry invalid at {registry_file}; using fallback digest"
|
|
106
|
-
else:
|
|
107
|
-
warning = None
|
|
108
|
-
contracts = data.get("contracts") if isinstance(data, dict) else None
|
|
109
|
-
if not isinstance(contracts, list):
|
|
110
|
-
contracts = DEFAULT_CONTRACT_REGISTRY["contracts"]
|
|
111
|
-
warning = warning or f"contract registry has no contracts array at {registry_file}; using fallback digest"
|
|
112
|
-
return [contract for contract in contracts if isinstance(contract, dict)], warning
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def _contract_fingerprint(root: Path, contracts: list[dict[str, Any]]) -> str:
|
|
116
|
-
digest = hashlib.sha256()
|
|
117
|
-
digest.update(json.dumps(contracts, ensure_ascii=False, sort_keys=True).encode("utf-8"))
|
|
118
|
-
for contract in contracts:
|
|
119
|
-
path = contract.get("path")
|
|
120
|
-
if not isinstance(path, str) or not path.strip():
|
|
121
|
-
continue
|
|
122
|
-
try:
|
|
123
|
-
digest.update((root / path).read_bytes())
|
|
124
|
-
except OSError:
|
|
125
|
-
digest.update(f"missing:{path}".encode("utf-8"))
|
|
126
|
-
return digest.hexdigest()[:16]
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def _build_contract_digest(root: Path) -> str:
|
|
130
|
-
contracts, warning = _load_contract_registry(root)
|
|
131
|
-
fingerprint = _contract_fingerprint(root, contracts)
|
|
132
|
-
lines = [
|
|
133
|
-
'<cowork-runtime host="claude-code" adapter="claude-code.hooks">',
|
|
134
|
-
f'<contract-digest fingerprint="{fingerprint}">',
|
|
135
|
-
"policy: repeat this short digest every hook; read full spec files only before listed actions.",
|
|
136
|
-
]
|
|
137
|
-
if warning:
|
|
138
|
-
lines.append(f"warning: {warning}")
|
|
139
|
-
for contract in contracts:
|
|
140
|
-
contract_id = contract.get("id")
|
|
141
|
-
path = contract.get("path")
|
|
142
|
-
if not isinstance(contract_id, str) or not contract_id.strip():
|
|
143
|
-
continue
|
|
144
|
-
path_text = path if isinstance(path, str) and path.strip() else "<missing-path>"
|
|
145
|
-
lines.append(f"- {contract_id}: {path_text}")
|
|
146
|
-
for item in _as_string_list(contract.get("digest"))[:2]:
|
|
147
|
-
lines.append(f" digest: {item}")
|
|
148
|
-
read_when = _as_string_list(contract.get("readWhen"))
|
|
149
|
-
if read_when:
|
|
150
|
-
lines.append(f" read_before: {'; '.join(read_when)}")
|
|
151
|
-
lines.extend(["</contract-digest>", "</cowork-runtime>"])
|
|
152
|
-
return "\n".join(lines)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def _load_common(root: Path) -> None:
|
|
156
|
-
scripts_dir = root / ".cowork-flow" / "scripts"
|
|
157
|
-
if str(scripts_dir) not in sys.path:
|
|
158
|
-
sys.path.insert(0, str(scripts_dir))
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def _get_active_task(root: Path, hook_input: dict[str, Any]) -> tuple[str | None, str, str]:
|
|
162
|
-
_load_common(root)
|
|
163
|
-
try:
|
|
164
|
-
from common.task.active_task import get_active_task # type: ignore[import-not-found]
|
|
165
|
-
except Exception:
|
|
166
|
-
return None, "no_task", "unavailable"
|
|
167
|
-
|
|
168
|
-
active = get_active_task(root, hook_input)
|
|
169
|
-
if not active.task_path:
|
|
170
|
-
return None, "no_task", active.source
|
|
171
|
-
|
|
172
|
-
task_dir = root / active.task_path
|
|
173
|
-
task_json = task_dir / "task.json"
|
|
174
|
-
try:
|
|
175
|
-
data = json.loads(task_json.read_text(encoding="utf-8"))
|
|
176
|
-
except (OSError, json.JSONDecodeError):
|
|
177
|
-
return active.task_path, "stale", active.source
|
|
178
|
-
|
|
179
|
-
status = data.get("status")
|
|
180
|
-
if not isinstance(status, str) or not status.strip():
|
|
181
|
-
status = "unknown"
|
|
182
|
-
return active.task_path, status.strip(), active.source
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def _resolve_runtime_context(root: Path, hook_input: dict[str, Any]) -> tuple[dict[str, Any] | None, str | None]:
|
|
186
|
-
_load_common(root)
|
|
187
|
-
try:
|
|
188
|
-
from common.task.active_task import ( # type: ignore[import-not-found]
|
|
189
|
-
bind_runtime_context,
|
|
190
|
-
read_runtime_context,
|
|
191
|
-
resolve_runtime_context_id,
|
|
192
|
-
)
|
|
193
|
-
except Exception:
|
|
194
|
-
return None, None
|
|
195
|
-
|
|
196
|
-
runtime_context_id = resolve_runtime_context_id(hook_input)
|
|
197
|
-
if not runtime_context_id:
|
|
198
|
-
return None, None
|
|
199
|
-
|
|
200
|
-
context = read_runtime_context(root, runtime_context_id)
|
|
201
|
-
if not context or context.get("scope") != "subagent" or context.get("status") == "closed":
|
|
202
|
-
return None, runtime_context_id
|
|
203
|
-
|
|
204
|
-
bound = bind_runtime_context(root, runtime_context_id, values=hook_input)
|
|
205
|
-
return bound or context, runtime_context_id
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
def _subagent_runtime_lines(context: dict[str, Any]) -> list[str]:
|
|
209
|
-
assignment = context.get("assignment") if isinstance(context.get("assignment"), dict) else {}
|
|
210
|
-
lines = [
|
|
211
|
-
f"Runtime context: {context.get('runtime_context_id')}",
|
|
212
|
-
f"Agent: {context.get('agent_type') or 'unknown'}",
|
|
213
|
-
"Scope: subagent",
|
|
214
|
-
"Do not run start/resume/task start/archive/commit/spawn.",
|
|
215
|
-
]
|
|
216
|
-
goal = assignment.get("goal") if isinstance(assignment, dict) else None
|
|
217
|
-
if isinstance(goal, str) and goal.strip():
|
|
218
|
-
lines.append(f"Goal: {goal.strip()}")
|
|
219
|
-
return lines
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
def _build_context(
|
|
223
|
-
root: Path,
|
|
224
|
-
task_path: str | None,
|
|
225
|
-
status: str,
|
|
226
|
-
source: str,
|
|
227
|
-
breadcrumbs: dict[str, str],
|
|
228
|
-
extra_lines: list[str] | None = None,
|
|
229
|
-
) -> str:
|
|
230
|
-
body = breadcrumbs.get(status) or "Refer to .cowork-flow/workflow.md for the current step."
|
|
231
|
-
if extra_lines:
|
|
232
|
-
body = "\n".join([body, *extra_lines])
|
|
233
|
-
if task_path is None:
|
|
234
|
-
header = f"Status: {status}\nSource: {source}"
|
|
235
|
-
else:
|
|
236
|
-
header = f"Task: {task_path}\nStatus: {status}\nSource: {source}"
|
|
237
|
-
|
|
238
|
-
return "\n\n".join(
|
|
239
|
-
[
|
|
240
|
-
"<claude-code-runtime>\nhooks: UserPromptSubmit, SessionStart\n</claude-code-runtime>",
|
|
241
|
-
_build_contract_digest(root),
|
|
242
|
-
f"<workflow-state>\n{header}\n{body}\n</workflow-state>",
|
|
243
|
-
]
|
|
244
|
-
)
|
|
245
|
-
|
|
246
|
-
|
|
247
40
|
def main() -> int:
|
|
248
|
-
if
|
|
41
|
+
if (
|
|
42
|
+
os.environ.get("COWORK_FLOW_HOOKS") == "0"
|
|
43
|
+
or os.environ.get("COWORK_FLOW_DISABLE_HOOKS") == "1"
|
|
44
|
+
):
|
|
249
45
|
return 0
|
|
250
|
-
|
|
251
|
-
hook_input = _normalize_hook_input(_read_hook_input())
|
|
46
|
+
hook_input = _read_input()
|
|
252
47
|
cwd_value = hook_input.get("cwd")
|
|
253
|
-
cwd =
|
|
254
|
-
|
|
48
|
+
cwd = (
|
|
49
|
+
Path(cwd_value)
|
|
50
|
+
if isinstance(cwd_value, str) and cwd_value.strip()
|
|
51
|
+
else Path.cwd()
|
|
52
|
+
)
|
|
53
|
+
root = _find_root(cwd)
|
|
255
54
|
if root is None:
|
|
256
55
|
return 0
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
additional_context = _build_context(root, task_path, status, source, breadcrumbs, extra_lines)
|
|
280
|
-
|
|
56
|
+
scripts_dir = root / ".cowork-flow" / "scripts"
|
|
57
|
+
sys.path.insert(0, str(scripts_dir))
|
|
58
|
+
from common.host.workflow_state_hook import build_hook_context
|
|
59
|
+
|
|
60
|
+
context = build_hook_context(
|
|
61
|
+
root,
|
|
62
|
+
hook_input,
|
|
63
|
+
host="claude-code",
|
|
64
|
+
adapter="claude-code.hooks",
|
|
65
|
+
preamble=(
|
|
66
|
+
(
|
|
67
|
+
"<claude-code-runtime>\n"
|
|
68
|
+
"hooks: UserPromptSubmit, SessionStart\n"
|
|
69
|
+
"</claude-code-runtime>"
|
|
70
|
+
),
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
event_name = (
|
|
74
|
+
hook_input.get("hook_event_name")
|
|
75
|
+
or hook_input.get("hookEventName")
|
|
76
|
+
or "UserPromptSubmit"
|
|
77
|
+
)
|
|
281
78
|
print(
|
|
282
79
|
json.dumps(
|
|
283
80
|
{
|
|
284
81
|
"hookSpecificOutput": {
|
|
285
82
|
"hookEventName": event_name,
|
|
286
|
-
"additionalContext":
|
|
83
|
+
"additionalContext": context,
|
|
287
84
|
}
|
|
288
85
|
},
|
|
289
86
|
ensure_ascii=False,
|
|
@@ -32,15 +32,24 @@ Load context before checking:
|
|
|
32
32
|
5. Read `git diff`.
|
|
33
33
|
6. Include `test_intent_review` in the review output for meaningful behavior breaks coverage and shallow tests rejection.
|
|
34
34
|
|
|
35
|
+
Authoritative internal protocols:
|
|
36
|
+
- `.cowork-flow/spec/protocols/review.md`
|
|
37
|
+
- `.cowork-flow/spec/protocols/decision-review.md`
|
|
38
|
+
- `.cowork-flow/spec/protocols/spec-maintenance.md`
|
|
39
|
+
|
|
40
|
+
Apply their output contracts exactly. Review output must preserve
|
|
41
|
+
`acceptanceId`, `findings`, `test_intent_review`, `resolution`, and
|
|
42
|
+
`specUpdates`.
|
|
43
|
+
|
|
35
44
|
Rules:
|
|
36
45
|
- Fix issues directly when they are clearly in scope.
|
|
37
46
|
- MUST NOT spawn, wait for, list, or close other agents.
|
|
38
47
|
- MUST NOT commit, archive, or mutate cowork-flow task state.
|
|
39
48
|
- Report findings, changed files, and exact verification commands.
|
|
40
|
-
- Include test intent findings that map tests back to
|
|
41
|
-
- BEFORE declaring
|
|
49
|
+
- Include test intent findings that map tests back to decision-anchor acceptance criteria or regression behavior.
|
|
50
|
+
- BEFORE declaring decision-anchor acceptance passed, run the spec-driven coding gate and
|
|
42
51
|
treat a nonzero exit as a hard blocker:
|
|
43
|
-
./.cowork-flow/run python .cowork-flow/scripts/common/gates/
|
|
52
|
+
./.cowork-flow/run python .cowork-flow/scripts/common/gates/validate_coding_standards.py --validate --repo-root .
|
|
44
53
|
This naturally enforces every rule the user added to
|
|
45
54
|
.cowork-flow/spec/backend/*.md and spec/frontend/*.md — they are not just
|
|
46
55
|
documentation but active validators. On violation, either fix the code or
|
|
@@ -33,16 +33,25 @@ Load context before editing:
|
|
|
33
33
|
6. Read the plan file linked from this task (check `<task>/task.json` `relatedFiles` for a plan path, or search `.cowork-flow/plans/` for a plan file referencing this task directory). Follow the plan steps in order — each step has Files, Action, Verify, and Expected fields.
|
|
34
34
|
7. For behavior-change tasks, create or verify `<task>/tdd.jsonl` before implementation or record a documented exemption.
|
|
35
35
|
|
|
36
|
+
Authoritative internal protocols:
|
|
37
|
+
- `.cowork-flow/spec/protocols/tdd.md`
|
|
38
|
+
- `.cowork-flow/spec/protocols/decision-review.md`
|
|
39
|
+
- `.cowork-flow/spec/protocols/spec-maintenance.md`
|
|
40
|
+
|
|
41
|
+
Apply their output contracts exactly. Implementation reports and `tdd.jsonl`
|
|
42
|
+
must preserve `acceptanceId`, `redCommand`, `redExitCode`, `greenCommand`,
|
|
43
|
+
`greenExitCode`, and `specUpdates`.
|
|
44
|
+
|
|
36
45
|
Rules:
|
|
37
46
|
- MUST NOT spawn, wait for, list, or close other agents.
|
|
38
47
|
- MUST NOT run task start, task finish, task archive, or unscoped resume.
|
|
39
48
|
- MUST NOT commit or push.
|
|
40
49
|
- Keep edits inside requested scope.
|
|
41
|
-
- Do not treat shallow tests as TDD evidence; red-green-refactor proof must include redCommand, redExitCode, greenCommand, greenExitCode, and
|
|
50
|
+
- Do not treat shallow tests as TDD evidence; red-green-refactor proof must include redCommand, redExitCode, greenCommand, greenExitCode, and decision-anchor acceptance ID mapping.
|
|
42
51
|
- Report changed files and exact verification commands.
|
|
43
52
|
- BEFORE editing any source file, run the spec-driven coding gate and treat a
|
|
44
53
|
nonzero exit as a hard blocker:
|
|
45
|
-
./.cowork-flow/run python .cowork-flow/scripts/common/gates/
|
|
54
|
+
./.cowork-flow/run python .cowork-flow/scripts/common/gates/validate_coding_standards.py --validate --repo-root .
|
|
46
55
|
Parse every *.md under .cowork-flow/spec/backend and spec/frontend; rules
|
|
47
56
|
declared there activate validators dynamically. On violation, fix the code
|
|
48
57
|
(do not disable the rule) and re-run until exit code 0.
|
|
@@ -5,8 +5,9 @@ sandbox_mode = "workspace-write"
|
|
|
5
5
|
developer_instructions = """
|
|
6
6
|
You are a dispatched default agent. Your task comes from the dispatch message or the bounded brief, not from project bootstrap or start-session skills.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
Do not run the project start-session workflow or try to spawn another
|
|
8
|
+
Treat AGENTS.md and project bootstrap text as constraints, not as the assigned
|
|
9
|
+
task. Do not run the project start-session workflow or try to spawn another
|
|
10
|
+
agent from this prompt.
|
|
10
11
|
|
|
11
12
|
Generic default-agent dispatch is advisory and cannot satisfy formal Implement
|
|
12
13
|
or Check completion. Follow the bounded prompt directly. Project rules are
|
|
@@ -5,8 +5,9 @@ sandbox_mode = "workspace-write"
|
|
|
5
5
|
developer_instructions = """
|
|
6
6
|
You are a dispatched explorer agent. Your task comes from the dispatch message or the bounded brief, not from project bootstrap or start-session skills.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
Do not run the project start-session workflow or try to spawn another
|
|
8
|
+
Treat AGENTS.md and project bootstrap text as constraints, not as the assigned
|
|
9
|
+
task. Do not run the project start-session workflow or try to spawn another
|
|
10
|
+
agent from this prompt.
|
|
10
11
|
|
|
11
12
|
Generic explorer dispatch is advisory and cannot satisfy formal Implement or
|
|
12
13
|
Check completion. Follow the bounded prompt directly. Project rules are
|
|
@@ -5,7 +5,8 @@ sandbox_mode = "workspace-write"
|
|
|
5
5
|
developer_instructions = """
|
|
6
6
|
You are a dispatched worker agent. Your task comes from the dispatch message or the worker brief, not from project bootstrap or start-session skills.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Treat AGENTS.md and project bootstrap text as constraints, not as the assigned
|
|
9
|
+
task.
|
|
9
10
|
If you can see any outer transport text such as Spawn one ... agent, ignore it. That text is for the coordinator, not for you.
|
|
10
11
|
Do not run the project start-session workflow or try to spawn another worker from this prompt.
|
|
11
12
|
|