cowork-flow 0.0.19 → 0.0.20
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/package.json +1 -1
- package/template/.agent/skills/start/SKILL.md +9 -4
- package/template/.codex/hooks/inject-workflow-state.py +30 -1
- package/template/.cowork-flow/.version +1 -1
- package/template/.cowork-flow/config.yaml +5 -0
- package/template/.cowork-flow/scripts/common/config.py +17 -0
- package/template/.cowork-flow/scripts/doctor.py +10 -0
- package/template/.cowork-flow/workflow.md +10 -1
package/package.json
CHANGED
|
@@ -13,9 +13,10 @@ Before loading state, classify the actual prompt. If it is a bounded delegated t
|
|
|
13
13
|
|
|
14
14
|
1. Read `AGENTS.md`.
|
|
15
15
|
2. Read `.cowork-flow/workflow.md`.
|
|
16
|
-
3.
|
|
17
|
-
4.
|
|
18
|
-
5. Read
|
|
16
|
+
3. Read `.cowork-flow/config.yaml` for `codex.post_ack_execution_grace_ms`.
|
|
17
|
+
4. Run `.cowork-flow/run resume` or `.\.cowork-flow\run.cmd resume` on Windows.
|
|
18
|
+
5. Read the active task PRD and JSONL indexes only when a task is active.
|
|
19
|
+
6. Read relevant `.cowork-flow/spec/*/index.md` files before code changes.
|
|
19
20
|
|
|
20
21
|
Report active task, workflow state, blockers, and the next phase.
|
|
21
22
|
|
|
@@ -51,4 +52,8 @@ Every dispatch prompt starts with:
|
|
|
51
52
|
Active task: <task-dir>
|
|
52
53
|
```
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
Prefer the `COWORK_DISPATCH_V1` envelope for `cowork-*` subagents, then wait for `COWORK_ACK <dispatch_id> <ack_token>` before sending `EXECUTE <dispatch_id>`.
|
|
56
|
+
|
|
57
|
+
Use per-dispatch post-ACK execution grace after sending `EXECUTE`. The default duration is `300000` ms and can be configured with `codex.post_ack_execution_grace_ms` in `.cowork-flow/config.yaml`. Record `execute_sent_at[dispatch_id]` and compute `deadline[dispatch_id] = execute_sent_at[dispatch_id] + codex.post_ack_execution_grace_ms`; do not use a shared/global deadline across children. After `EXECUTE`, missing output or missing compass/status file is not proof that the child is stuck. Do not close a child only because it is still reading startup rules, AGENTS.md, workflow docs, specs, or task context. If `list_agents` still shows it running, continue waiting through grace. Grace expiration for one `dispatch_id` is a review checkpoint for that child only, not a close trigger and not evidence about other children. If progress, compass, or status files exist, keep waiting. Only close after wrong dispatch evidence, child completion, or user cancellation.
|
|
58
|
+
|
|
59
|
+
After execution, use `wait_agent`, review the output, inspect `list_agents`, and `close_agent`.
|
|
@@ -144,6 +144,21 @@ def _get_dispatch_mode(root: Path) -> str:
|
|
|
144
144
|
return "sub-agent"
|
|
145
145
|
|
|
146
146
|
|
|
147
|
+
def _get_post_ack_execution_grace_ms(root: Path) -> int:
|
|
148
|
+
_load_common(root)
|
|
149
|
+
try:
|
|
150
|
+
from common.config import ( # type: ignore[import-not-found]
|
|
151
|
+
DEFAULT_CODEX_POST_ACK_EXECUTION_GRACE_MS,
|
|
152
|
+
get_codex_post_ack_execution_grace_ms,
|
|
153
|
+
)
|
|
154
|
+
except Exception:
|
|
155
|
+
return 300000
|
|
156
|
+
try:
|
|
157
|
+
return get_codex_post_ack_execution_grace_ms(root)
|
|
158
|
+
except Exception:
|
|
159
|
+
return DEFAULT_CODEX_POST_ACK_EXECUTION_GRACE_MS
|
|
160
|
+
|
|
161
|
+
|
|
147
162
|
def _get_active_task(root: Path, hook_input: dict[str, Any]) -> tuple[str | None, str, str]:
|
|
148
163
|
_load_common(root)
|
|
149
164
|
try:
|
|
@@ -174,6 +189,7 @@ def _build_context(
|
|
|
174
189
|
source: str,
|
|
175
190
|
breadcrumbs: dict[str, str],
|
|
176
191
|
dispatch_mode: str,
|
|
192
|
+
post_ack_execution_grace_ms: int,
|
|
177
193
|
) -> str:
|
|
178
194
|
body = breadcrumbs.get(status) or "Refer to .cowork-flow/workflow.md for the current step."
|
|
179
195
|
if task_path is None:
|
|
@@ -184,6 +200,11 @@ def _build_context(
|
|
|
184
200
|
return "\n\n".join(
|
|
185
201
|
[
|
|
186
202
|
f"<codex-mode>{dispatch_mode}</codex-mode>",
|
|
203
|
+
(
|
|
204
|
+
"<codex-runtime>\n"
|
|
205
|
+
f"post_ack_execution_grace_ms: {post_ack_execution_grace_ms}\n"
|
|
206
|
+
"</codex-runtime>"
|
|
207
|
+
),
|
|
187
208
|
f"<workflow-state>\n{header}\n{body}\n</workflow-state>",
|
|
188
209
|
]
|
|
189
210
|
)
|
|
@@ -202,12 +223,20 @@ def main() -> int:
|
|
|
202
223
|
|
|
203
224
|
breadcrumbs = _load_breadcrumbs(root)
|
|
204
225
|
dispatch_mode = _get_dispatch_mode(root)
|
|
226
|
+
post_ack_execution_grace_ms = _get_post_ack_execution_grace_ms(root)
|
|
205
227
|
task_path, status, source = _get_active_task(root, hook_input)
|
|
206
228
|
if _is_delegated_prompt(hook_input):
|
|
207
229
|
task_path = None
|
|
208
230
|
status = "delegated_subtask"
|
|
209
231
|
source = "prompt"
|
|
210
|
-
additional_context = _build_context(
|
|
232
|
+
additional_context = _build_context(
|
|
233
|
+
task_path,
|
|
234
|
+
status,
|
|
235
|
+
source,
|
|
236
|
+
breadcrumbs,
|
|
237
|
+
dispatch_mode,
|
|
238
|
+
post_ack_execution_grace_ms,
|
|
239
|
+
)
|
|
211
240
|
|
|
212
241
|
print(
|
|
213
242
|
json.dumps(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.
|
|
1
|
+
0.0.20
|
|
@@ -24,6 +24,11 @@ max_journal_lines: 2000
|
|
|
24
24
|
# inline: hint that main session should perform implementation/check directly.
|
|
25
25
|
codex:
|
|
26
26
|
dispatch_mode: "sub-agent"
|
|
27
|
+
# Grace duration after each subagent ACKs and receives EXECUTE.
|
|
28
|
+
# This is a per-dispatch duration, not a shared/global deadline.
|
|
29
|
+
# During this window, missing output or missing compass/status files do not
|
|
30
|
+
# prove the child is stuck while it loads task context.
|
|
31
|
+
post_ack_execution_grace_ms: 300000
|
|
27
32
|
|
|
28
33
|
#-------------------------------------------------------------------------------
|
|
29
34
|
# Task Lifecycle Hooks
|
|
@@ -16,6 +16,7 @@ from .paths import DIR_WORKFLOW, get_repo_root
|
|
|
16
16
|
DEFAULT_SESSION_COMMIT_MESSAGE = "chore: record journal"
|
|
17
17
|
DEFAULT_MAX_JOURNAL_LINES = 2000
|
|
18
18
|
DEFAULT_CODEX_DISPATCH_MODE = "sub-agent"
|
|
19
|
+
DEFAULT_CODEX_POST_ACK_EXECUTION_GRACE_MS = 300000
|
|
19
20
|
|
|
20
21
|
CONFIG_FILE = "config.yaml"
|
|
21
22
|
|
|
@@ -139,3 +140,19 @@ def get_codex_dispatch_mode(repo_root: Path | None = None) -> str:
|
|
|
139
140
|
if mode in {"sub-agent", "inline"}:
|
|
140
141
|
return str(mode)
|
|
141
142
|
return DEFAULT_CODEX_DISPATCH_MODE
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def get_codex_post_ack_execution_grace_ms(repo_root: Path | None = None) -> int:
|
|
146
|
+
"""Get the post-ACK execution grace duration for Codex subagent dispatch."""
|
|
147
|
+
config = _load_config(repo_root)
|
|
148
|
+
codex = config.get("codex")
|
|
149
|
+
if not isinstance(codex, dict):
|
|
150
|
+
return DEFAULT_CODEX_POST_ACK_EXECUTION_GRACE_MS
|
|
151
|
+
value = codex.get("post_ack_execution_grace_ms", DEFAULT_CODEX_POST_ACK_EXECUTION_GRACE_MS)
|
|
152
|
+
try:
|
|
153
|
+
parsed = int(value)
|
|
154
|
+
except (ValueError, TypeError):
|
|
155
|
+
return DEFAULT_CODEX_POST_ACK_EXECUTION_GRACE_MS
|
|
156
|
+
if parsed <= 0:
|
|
157
|
+
return DEFAULT_CODEX_POST_ACK_EXECUTION_GRACE_MS
|
|
158
|
+
return parsed
|
|
@@ -15,6 +15,10 @@ REQUIRED_START_SNIPPETS = [
|
|
|
15
15
|
"This skill is for the main session",
|
|
16
16
|
"bounded delegated task should use `entry-boundary`",
|
|
17
17
|
"Main repository changes follow `Plan -> Implement -> Check -> Finish`",
|
|
18
|
+
"post-ACK execution grace",
|
|
19
|
+
"codex.post_ack_execution_grace_ms",
|
|
20
|
+
"execute_sent_at[dispatch_id]",
|
|
21
|
+
"shared/global deadline",
|
|
18
22
|
]
|
|
19
23
|
|
|
20
24
|
REQUIRED_ENTRY_BOUNDARY_SNIPPETS = [
|
|
@@ -45,6 +49,12 @@ REQUIRED_WORKFLOW_DISPATCH_SNIPPETS = [
|
|
|
45
49
|
"COWORK_DISPATCH_V1",
|
|
46
50
|
"COWORK_ACK",
|
|
47
51
|
"followup_task",
|
|
52
|
+
"post-ACK execution grace",
|
|
53
|
+
"codex.post_ack_execution_grace_ms",
|
|
54
|
+
"execute_sent_at[dispatch_id]",
|
|
55
|
+
"deadline[dispatch_id] = execute_sent_at[dispatch_id] + codex.post_ack_execution_grace_ms",
|
|
56
|
+
"shared/global deadline",
|
|
57
|
+
"After `EXECUTE <dispatch_id>`, no reply or no compass/status file while the child loads context is inconclusive.",
|
|
48
58
|
"Formal execution uses `cowork-research`, `cowork-implement`, or `cowork-check`.",
|
|
49
59
|
"Generic `worker` dispatch is best-effort only.",
|
|
50
60
|
]
|
|
@@ -34,7 +34,7 @@ The active task is in planning. Finish prd.md, curate implement.jsonl and check.
|
|
|
34
34
|
[/workflow-state:planning]
|
|
35
35
|
|
|
36
36
|
[workflow-state:in_progress]
|
|
37
|
-
The active task is in progress. Main session dispatches cowork-implement work according to the plan, then cowork-check after integration. Every spawn_agent call uses fork_turns="none" and a COWORK_DISPATCH_V1 envelope. Main session waits for COWORK_ACK, sends EXECUTE with followup_task, verifies child output, lists agents, and closes children.
|
|
37
|
+
The active task is in progress. Main session dispatches cowork-implement work according to the plan, then cowork-check after integration. Every spawn_agent call uses fork_turns="none" and a COWORK_DISPATCH_V1 envelope. Main session waits for COWORK_ACK, sends EXECUTE with followup_task, then uses per-dispatch post-ACK execution grace while each child loads context. Main session verifies child output, lists agents, and closes children only after completion or clear failure evidence.
|
|
38
38
|
[/workflow-state:in_progress]
|
|
39
39
|
|
|
40
40
|
[workflow-state:completed]
|
|
@@ -115,7 +115,16 @@ spawn_agent(
|
|
|
115
115
|
- Use `wait_agent` for `COWORK_ACK <dispatch_id> <ack_token>` before execution.
|
|
116
116
|
- Missing or mismatched `COWORK_ACK` means the task is not dispatched.
|
|
117
117
|
- Only after a matching ACK, send `EXECUTE <dispatch_id>` with `followup_task`.
|
|
118
|
+
- Record `execute_sent_at[dispatch_id]` when `EXECUTE <dispatch_id>` is sent.
|
|
119
|
+
- Compute `deadline[dispatch_id] = execute_sent_at[dispatch_id] + codex.post_ack_execution_grace_ms`; do not use a shared/global deadline across children.
|
|
120
|
+
- After `EXECUTE <dispatch_id>`, no reply or no compass/status file while the child loads context is inconclusive.
|
|
121
|
+
- Use post-ACK execution grace for execution startup before judging execution health. The default is `300000` ms and can be configured with `codex.post_ack_execution_grace_ms` in `.cowork-flow/config.yaml`.
|
|
122
|
+
- Do not call `close_agent` only because the executing child has not produced a compass/status file.
|
|
123
|
+
- If `list_agents` still shows the child running, continue waiting through post-ACK execution grace instead of closing it.
|
|
124
|
+
- Post-ACK execution grace expiration for one `dispatch_id` is a review checkpoint for that child only, not a close trigger and not evidence about other children.
|
|
125
|
+
- If progress, compass, or status files exist, continue waiting and do not close solely because grace expired.
|
|
118
126
|
- If a child reports another `dispatch_id`, close that child and respawn the intended task.
|
|
127
|
+
- An executing child may be closed only after wrong-dispatch evidence, child completion, or user cancellation.
|
|
119
128
|
- 用 `wait_agent` 等待子 agent 返回。
|
|
120
129
|
- 用 `list_agents` 确认没有遗留 running child。
|
|
121
130
|
- 验收子 agent 汇报的文件、命令和结果;不只信“已完成”文本。
|