@ikon85/agent-workflow-kit 0.27.1 → 0.29.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.
Files changed (79) hide show
  1. package/.agents/skills/ask-matt/SKILL.md +2 -2
  2. package/.agents/skills/board-to-waves/SKILL.md +13 -3
  3. package/.agents/skills/grill-me/SKILL.md +1 -1
  4. package/.agents/skills/grill-with-docs/SKILL.md +1 -1
  5. package/.agents/skills/kit-update/SKILL.md +12 -0
  6. package/.agents/skills/orchestrate-wave/SKILL.md +68 -21
  7. package/.agents/skills/orchestrate-wave/references/builder-contract.md +6 -4
  8. package/.agents/skills/retro/SKILL.md +24 -1
  9. package/.agents/skills/scale-check/SKILL.md +2 -2
  10. package/.agents/skills/setup-workflow/SKILL.md +44 -1
  11. package/.agents/skills/setup-workflow/workflow-overview.md +5 -5
  12. package/.agents/skills/tdd/SKILL.md +68 -14
  13. package/.agents/skills/to-issues/SKILL.md +104 -29
  14. package/.agents/skills/to-prd/SKILL.md +13 -3
  15. package/.agents/skills/to-waves/SKILL.md +16 -4
  16. package/.agents/skills/verify-spike/SKILL.md +1 -1
  17. package/.agents/skills/wrapup/SKILL.md +14 -3
  18. package/.claude/hooks/drift-guard.py +5 -2
  19. package/.claude/hooks/kit-origin-edit-hint.py +64 -0
  20. package/.claude/skills/ask-matt/SKILL.md +2 -2
  21. package/.claude/skills/board-to-waves/SKILL.md +13 -3
  22. package/.claude/skills/codex-build/SKILL.md +69 -23
  23. package/.claude/skills/codex-review/SKILL.md +47 -37
  24. package/.claude/skills/grill-me/SKILL.md +1 -1
  25. package/.claude/skills/grill-me-codex/SKILL.md +45 -34
  26. package/.claude/skills/grill-with-docs/SKILL.md +1 -1
  27. package/.claude/skills/grill-with-docs-codex/SKILL.md +46 -34
  28. package/.claude/skills/kit-update/SKILL.md +12 -0
  29. package/.claude/skills/orchestrate-wave/SKILL.md +68 -21
  30. package/.claude/skills/orchestrate-wave/references/builder-contract.md +6 -4
  31. package/.claude/skills/retro/SKILL.md +23 -0
  32. package/.claude/skills/scale-check/SKILL.md +2 -2
  33. package/.claude/skills/setup-workflow/SKILL.md +44 -1
  34. package/.claude/skills/setup-workflow/workflow-overview.md +5 -5
  35. package/.claude/skills/skill-manifest.json +1 -1
  36. package/.claude/skills/tdd/SKILL.md +68 -14
  37. package/.claude/skills/to-issues/SKILL.md +104 -29
  38. package/.claude/skills/to-prd/SKILL.md +13 -3
  39. package/.claude/skills/to-waves/SKILL.md +16 -4
  40. package/.claude/skills/verify-spike/SKILL.md +1 -1
  41. package/.claude/skills/wrapup/SKILL.md +14 -3
  42. package/README.md +70 -7
  43. package/agent-workflow-kit.package.json +99 -43
  44. package/docs/adr/0001-consumer-divergence-policy.md +49 -0
  45. package/docs/agents/wave-anchor-template.md +1 -1
  46. package/docs/research/wave-152-consumer-acceptance.md +98 -0
  47. package/package.json +1 -1
  48. package/scripts/board-sync.py +187 -12
  49. package/scripts/build-kit.test.mjs +42 -1
  50. package/scripts/codex-exec-scenarios/fake-codex.mjs +152 -0
  51. package/scripts/codex-exec.sh +566 -0
  52. package/scripts/codex-exec.test.mjs +815 -0
  53. package/scripts/codex_proc.py +602 -0
  54. package/scripts/find-by-marker.py +68 -0
  55. package/scripts/marker_lib.py +88 -0
  56. package/scripts/pr-body-check.py +34 -6
  57. package/scripts/pr_body_e2e.py +83 -0
  58. package/scripts/render-anchor.py +111 -0
  59. package/scripts/test_board_sync.py +208 -0
  60. package/scripts/test_census_backstop.py +56 -3
  61. package/scripts/test_marker_lib.py +154 -0
  62. package/scripts/test_orchestrate_wave_contract.py +116 -0
  63. package/scripts/test_pr_body_check.py +245 -0
  64. package/scripts/test_render_anchor.py +267 -0
  65. package/scripts/test_retro_wrapup_contract.py +117 -0
  66. package/scripts/test_skill_codex_exec_lifecycle.py +123 -0
  67. package/scripts/test_tdd_contract.py +78 -0
  68. package/src/cli.mjs +44 -8
  69. package/src/commands/diff.mjs +5 -2
  70. package/src/commands/init.mjs +12 -0
  71. package/src/commands/own.mjs +16 -0
  72. package/src/commands/uninstall.mjs +8 -1
  73. package/src/commands/update.mjs +37 -9
  74. package/src/lib/bundle.mjs +14 -0
  75. package/src/lib/consumerPath.mjs +30 -0
  76. package/src/lib/manifest.mjs +18 -0
  77. package/src/lib/ownedDiff.mjs +88 -0
  78. package/src/lib/updateCandidate.mjs +14 -0
  79. package/src/lib/updateReconcile.mjs +45 -6
@@ -11,11 +11,13 @@ This is a **deliberate, high-stakes tool** — reach for it on auth, data models
11
11
 
12
12
  ## Prerequisites (verify once, fast)
13
13
 
14
- - Codex CLI installed and recent: `codex --version` (need 0.130; the default `gpt-5.5` model errors on older CLIs).
15
- - Codex authenticated: a prior `codex login` (ChatGPT account is fine). If a run returns an auth/model error, surface it to the user — do not silently retry.
14
+ - Let `scripts/codex-exec.sh` preflight Codex before launch. It enforces the
15
+ exact tested-version allowlist, authentication, platform, and capabilities;
16
+ surface any failure to the user rather than retrying silently.
16
17
  - Do NOT pin `-m` unless the user asks. The user's `~/.codex/config.toml` default model is used. Pinning `gpt-5.x-codex` variants fails on ChatGPT-account auth.
17
18
  - **Echo the active model before Round 1** so the user can confirm: read the `model` line from `~/.codex/config.toml` (absent = "CLI default"); state it alongside the resolved tunables. If the user objects, stop before burning a round.
18
- - **Sandbox flag differs between the two commands.** `codex exec` accepts `-s read-only`. `codex exec resume` does NOT — it rejects `-s` ("unexpected argument"). On resume you MUST force read-only via `-c sandbox_mode="read-only"`, because `config.toml` may default `sandbox_mode` to `danger-full-access` (+ `approval_policy="never"`) — which would let Codex WRITE files mid-loop. This is the single most important safety detail in this skill: verified end-to-end on 2026-06-04.
19
+ - Use `scripts/codex-exec.sh` for every round. Its `review` profile persists the
20
+ initial `read-only` mode across resumes and rejects mode drift.
19
21
 
20
22
  ## Tunable variables (read from skill args, else default)
21
23
 
@@ -37,7 +39,7 @@ The invocation itself is the kickoff. Confirm scope in one line: what is being p
37
39
 
38
40
  Do real planning: read the relevant code, think through the approach, surface decisions and tradeoffs. Then write the plan to `PLAN_FILE` in this structure:
39
41
 
40
- > **Where to write it:** `PLAN.md` + `PLAN-REVIEW-LOG.md` are per-session scratch — write them in the working directory the implementing session will actually use, and run Codex from there (`-C <dir>` on the round-1 `exec`; `exec resume` rejects both `-C` and `-s`, so run resume from that cwd and force read-only via `-c sandbox_mode="read-only"`). A project may gitignore these files, so don't rely on git to carry them across checkouts/worktrees. In worktree-based repos, create the issue worktree BEFORE this write and plan inside it.
42
+ > **Where to write it:** `PLAN.md` + `PLAN-REVIEW-LOG.md` are per-session scratch — write them in the working directory the implementing session will actually use, and invoke the wrapper from that directory. A project may gitignore these files, so don't rely on git to carry them across checkouts/worktrees. In worktree-based repos, create the issue worktree BEFORE this write and plan inside it.
41
43
 
42
44
  ```markdown
43
45
  # Plan: <task>
@@ -69,60 +71,66 @@ Show the user the plan inline and say you're sending it to Codex for adversarial
69
71
 
70
72
  ### Step 2 — The loop
71
73
 
72
- Maintain `ROUND` (start 1) and `THREAD_ID` (empty until round 1 returns).
74
+ Maintain `ROUND` (start 1) and the wrapper's opaque `RUN_ID`.
73
75
 
74
76
  **The review prompt** sent to Codex each round (adjust the task line):
75
77
 
76
78
  > You are an adversarial reviewer for an implementation plan. Be skeptical and specific — your job is to find what breaks, not to be agreeable. Read the plan at `PLAN.md` (and any repo files you need; you are read-only). Identify concrete flaws: security holes, race conditions, missing edge cases, schema conflicts, wrong assumptions, observability gaps, simpler alternatives. For each, give a one-line fix. Do NOT modify any files. End your reply with EXACTLY one line: `VERDICT: APPROVED` if the plan is sound enough to implement, or `VERDICT: REVISE` if it still has material problems.
77
79
 
78
- **Round 1** (creates the session capture `thread_id`):
79
-
80
- Stream `--json` to a FILE, never pipe to `grep` — `codex exec --json | grep` deadlocks on codex-cli ≥0.137. **Always launch with `< /dev/null`** — a backgrounded `codex exec … &` without it blocks on stdin and sits at **0 CPU / 0 bytes** forever (the #1 cause of the "silent hang"; verified 2026-06-09). Background it so a **90s liveness probe** still catches a genuine sandbox deadlock.
80
+ **Round 1** creates the session and returns the opaque run ID plus the report:
81
81
 
82
82
  ```bash
83
- CODEX_TMP="/tmp/codex-$(pwd | sha1sum | cut -c1-8)"; mkdir -p "$CODEX_TMP" # run-unique per worktree cwd: STABLE across round-1+resume turns, collision-free under parallel sessions
84
- codex exec -s read-only --json -o $CODEX_TMP/verdict.txt "$(cat REVIEW_PROMPT)" \
85
- < /dev/null > $CODEX_TMP/r1.jsonl 2>/dev/null &
86
- CODEX_PID=$!
87
- sleep 90 # liveness probe (REQUIRED)
88
- if kill -0 "$CODEX_PID" 2>/dev/null; then
89
- CPU=$(ps -o time= -p "$CODEX_PID" 2>/dev/null | tr -dc '0-9:') # cumulative CPU, e.g. 00:00:00
90
- BYTES=$(wc -c < $CODEX_TMP/r1.jsonl 2>/dev/null || echo 0)
91
- if [ "${CPU:-00:00:00}" = "00:00:00" ] && [ "${BYTES:-0}" -eq 0 ]; then
92
- kill -9 "$CODEX_PID" 2>/dev/null; echo "CODEX-HUNG" # alive + 0 CPU + 0 bytes = blocked, NOT working
93
- fi
83
+ if ROUND_RESULT=$(scripts/codex-exec.sh new --profile review --mode read-only --prompt "$REVIEW_PROMPT"); then
84
+ RUN_ID=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["runId"])')
85
+ CODEX_REPORT=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["verdict"])')
86
+ else
87
+ FAILURE_RESULT=$(scripts/codex-exec.sh handle-failure --result "$ROUND_RESULT") || :
88
+ printf '%s\n' "$FAILURE_RESULT" >&2
89
+ exit 1
94
90
  fi
95
- wait "$CODEX_PID" 2>/dev/null
96
- THREAD_ID=$(grep -o '"thread_id":"[^"]*"' $CODEX_TMP/r1.jsonl | head -1 | cut -d'"' -f4)
97
91
  ```
98
- - **`CODEX-HUNG` printed** (alive + 0 CPU + 0 bytes at 90s) → **first suspect the stdin block**: confirm the launch has `< /dev/null` and retry. That fixes it in nearly every case. **NEVER `pgrep`/`kill` codex procs to "clear contention"** — that murders the user's live, unrelated codex sessions and does **not** fix a stdin hang. Only if `< /dev/null` is present and it still hangs (genuine sandbox deadlock) → **STOP**: tell the user, offer to proceed without the cross-model review or retry once. Don't touch other codex processes.
99
- - **Healthy:** CPU climbs past `00:00:00` and/or `$CODEX_TMP/r1.jsonl` grows; `THREAD_ID` parses; critique lands in `$CODEX_TMP/verdict.txt`. `2>/dev/null` hides cosmetic MCP/auth noise.
100
- - **Clean finish but no verdict file + no `THREAD_ID`** = auth/model failure → stop, tell the user.
101
92
 
102
- **Rounds 2..MAX** (resume the SAME session Codex remembers its earlier critiques, won't re-litigate settled points):
93
+ **Rounds 2..MAX** resume the same wrapper-owned session; do not pass a mode
94
+ again because the wrapper enforces the persisted read-only mode:
103
95
 
104
96
  ```bash
105
- # NOTE: resume rejects -s. Force read-only via -c sandbox_mode, or Codex
106
- # inherits config.toml (possibly danger-full-access) and could write files.
107
- CODEX_TMP="/tmp/codex-$(pwd | sha1sum | cut -c1-8)"; mkdir -p "$CODEX_TMP" # run-unique per worktree cwd: STABLE across round-1+resume turns, collision-free under parallel sessions
108
- codex exec resume "$THREAD_ID" -c sandbox_mode="read-only" --json \
109
- -o $CODEX_TMP/verdict.txt \
110
- "I revised the plan. Re-review PLAN.md. Same rules. End with VERDICT: APPROVED or VERDICT: REVISE." \
111
- < /dev/null 2>/dev/null >/dev/null &
97
+ if ROUND_RESULT=$(scripts/codex-exec.sh resume "$RUN_ID" --prompt "I revised the plan. Re-review PLAN.md. Same rules. End with VERDICT: APPROVED or VERDICT: REVISE."); then
98
+ CODEX_REPORT=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["verdict"])')
99
+ else
100
+ FAILURE_RESULT=$(scripts/codex-exec.sh handle-failure --result "$ROUND_RESULT" --run-id "$RUN_ID") || :
101
+ printf '%s\n' "$FAILURE_RESULT" >&2
102
+ exit 1
103
+ fi
112
104
  ```
113
- Wrap resume in the **same 90s liveness probe** (background + `wait`). Resume discards the `--json` stream, so probe on the verdict file: `BYTES=$(wc -c < $CODEX_TMP/verdict.txt)` plus the `CPU` check — `00:00:00` CPU + empty verdict at 90s → kill, treat as `CODEX-HUNG`, same STOP path as round 1.
114
105
 
115
- **Overall ceiling (both rounds):** the 90s probe catches silent hangs, not long stuck runs. Cap every `codex exec` / `codex exec resume` at **10 minutes** — via Claude Code's Bash tool pass `timeout: 600000` on the tool call (the default 2-minute tool timeout would kill real reviews mid-run); in a plain shell prefix `timeout 600` (macOS: `gtimeout 600` via coreutils). If the ceiling trips, treat it as a failed round: stop and tell the user rather than retrying blind.
106
+ The wrapper owns stdin closure, hang detection, the overall timeout, stderr
107
+ redaction, and its process group. `handle-failure` surfaces the structured
108
+ status and cleanup metadata, then the caller stops before report handling. A
109
+ surfaced `HUNG` returns to the user for the choice to retry once with a fresh
110
+ run or continue without cross-model review. Never inspect, signal, or kill
111
+ foreign Codex processes.
112
+
113
+ Separately, cancellation or a decision to stop orchestration after an OK round
114
+ but before normal finalize must abort the known run:
116
115
 
117
- Both `codex exec` and `codex exec resume` support `--json` (stream → parse `thread_id` first round) and `-o/--output-last-message` (verdict capture).
116
+ ```bash
117
+ scripts/codex-exec.sh abort "$RUN_ID"
118
+ ```
118
119
 
119
120
  **Each round, after Codex returns:**
120
- 1. Read `$CODEX_TMP/verdict.txt`. Append to `LOG_FILE`: `## Round <n> — Codex` + the full critique.
121
+ 1. Read `CODEX_REPORT`. Append to `LOG_FILE`: `## Round <n> — Codex` + the full critique.
121
122
  2. Grep the last line for the verdict token.
122
123
  - `VERDICT: APPROVED` → break the loop, go to Step 3 (converged).
123
124
  - `VERDICT: REVISE` → Claude reads the critique, decides **what's actually worth acting on** (Claude has final say — Codex advises, it does not command). Revise `PLAN_FILE`. Append to `LOG_FILE`: `### Claude's response` + what you changed and what you rejected and why. Increment `ROUND`.
124
125
  3. If `ROUND > MAX_ROUNDS` → break to Step 3 (deadlock).
125
126
 
127
+ After harvesting the final report and updating the log, delete the successful
128
+ run state:
129
+
130
+ ```bash
131
+ scripts/codex-exec.sh finalize "$RUN_ID"
132
+ ```
133
+
126
134
  ### Step 3 — Resolution (human gate #2)
127
135
 
128
136
  **If APPROVED:** Present to the user — the final `PLAN_FILE`, a 3-bullet summary of what the argument improved, and the round count. Ask: *"Plan survived N rounds of Codex. Implement it now — Codex builds it (`/codex-build`), Claude builds it, or stop here?"* Only on a yes is code written. **No code is written during the loop.** If the user picks Codex, invoke the `codex-build` skill with `SPEC_FILE=PLAN.md` and the same `LOG_FILE` — roles flip (Codex writes in a bounded workspace-write sandbox, Claude reviews the diff) and the build rounds append to the same log.
@@ -131,7 +139,9 @@ Both `codex exec` and `codex exec resume` support `--json` (stream → parse `th
131
139
 
132
140
  ## Hard rules
133
141
 
134
- - Codex is read-only EVERY round `-s read-only` for the first call, `-c sandbox_mode="read-only"` for every resume (resume has no `-s`). It never writes. If you're tempted to give it write access, stop — that's a different skill.
142
+ - Codex is read-only EVERY round. Establish that once with the wrapper's
143
+ `review` + `read-only` new call; every resume inherits it. If you're tempted
144
+ to give it write access, stop — that's a different skill.
135
145
  - The loop ALWAYS terminates at `MAX_ROUNDS`. No unbounded recursion.
136
146
  - Claude is the final arbiter on every REVISE — incorporate good critiques, reject bad ones *with a reason logged*. Don't cave to Codex on everything (that defeats the cross-model check) and don't ignore it (that defeats the point).
137
147
  - Code only after human gate #2.
@@ -48,7 +48,7 @@ Once all decisions are made (plan locked, before sign-off/handoff) and the sessi
48
48
 
49
49
  ## Re-grill reconcile — execute-ready (Wave 26)
50
50
 
51
- Applies when you **re-grill an issue that already exists** (a leaf of a grilled epic, or a child of an anchor) — the most common re-grill path, since campaign HITL slices route via `/grill-me → /tdd`. Goal: the rooted sub-graph comes out **execute-ready**, never silent drift. (grill-me has no docs layer — CONTEXT.md/ADR don't apply; core rules identical to grill-with-docs §"Re-Grill Reconcile".)
51
+ Applies when you **re-grill an issue that already exists** (a leaf of a grilled epic, or a child of an anchor) — the most common re-grill path, since campaign HITL slices route via `/grill-me → /implement`. Goal: the rooted sub-graph comes out **execute-ready**, never silent drift. (grill-me has no docs layer — CONTEXT.md/ADR don't apply; core rules identical to grill-with-docs §"Re-Grill Reconcile".)
52
52
 
53
53
  1. **Read parent-anchor decisions FIRST** — fetch the anchor body + its PRD/key decisions, take the seam decision **from there**. Do not re-derive the architecture from the leaf (lesson: a leaf whose central decision was never read got re-litigated through question rounds). For an atomic leaf, its own body/PRD is the reference.
54
54
  2. **Check the leaf for internal contradiction**: a body that contradicts itself ("no new UI" + "build a name field") or the anchor decision → **no execute**. Likewise a leaf that says *"final cut depends on #X"* via `<!-- final-cut-depends-on: #X -->` where **#X is closed** without resolving the cut.
@@ -41,7 +41,7 @@ For a cross-cutting plan, run `python3 .claude/hooks/drift-guard.py --census-sta
41
41
 
42
42
  When the decision tree is resolved and we're aligned, **write the agreed plan to `PLAN.md`** in this structure, then move to Act 2:
43
43
 
44
- > **Where to write it:** `PLAN.md` + `PLAN-REVIEW-LOG.md` are per-session scratch — write them in the working directory the implementing session will actually use, and run Codex from there (`-C <dir>` on the round-1 `exec`; `exec resume` rejects both `-C` and `-s`, so run resume from that cwd and force read-only via `-c sandbox_mode="read-only"`). A project may gitignore these files, so don't rely on git to carry them across checkouts/worktrees. In worktree-based repos, create the issue worktree BEFORE this write and plan inside it.
44
+ > **Where to write it:** `PLAN.md` + `PLAN-REVIEW-LOG.md` are per-session scratch — write them in the working directory the implementing session will actually use, and invoke the wrapper from that directory. A project may gitignore these files, so don't rely on git to carry them across checkouts/worktrees. In worktree-based repos, create the issue worktree BEFORE this write and plan inside it.
45
45
 
46
46
  ```markdown
47
47
  # Plan: <task>
@@ -76,8 +76,9 @@ Act 1 (grill) complete — plan locked with the user. MAX_ROUNDS=<n>.
76
76
  Now hand the locked plan to Codex for adversarial review. Same engine, mechanics verified end-to-end (2026-06-04).
77
77
 
78
78
  ### Prerequisites (verify once, fast)
79
- - `codex --version` 0.130 (older CLIs error on the default `gpt-5.5` model).
80
- - Codex authenticated (prior `codex login`; ChatGPT account is fine). On auth/model error, surface it — don't silently retry.
79
+ - Let `scripts/codex-exec.sh` preflight Codex before launch. It enforces the
80
+ exact tested-version allowlist, authentication, platform, and capabilities;
81
+ surface any failure rather than retrying silently.
81
82
  - Do NOT pin `-m`. Use the config default. Pinning `gpt-5.x-codex` variants 400s on ChatGPT-account auth.
82
83
  - **Echo the active model before Round 1** so the user can confirm: read the `model` line from `~/.codex/config.toml` (absent = "CLI default"); state it alongside the resolved tunables. If the user objects, stop before burning a round.
83
84
 
@@ -93,50 +94,59 @@ If invoked with e.g. `rounds=3`, use that for `MAX_ROUNDS`. Echo resolved values
93
94
  ### The review prompt (sent each round)
94
95
  > You are an adversarial reviewer for an implementation plan. Be skeptical and specific — your job is to find what breaks, not to be agreeable. Read the plan at `PLAN.md` and any repo files you need (you are read-only). Identify concrete flaws: security holes, race conditions, missing edge cases, schema conflicts, wrong assumptions, observability gaps, simpler alternatives. For each, give a one-line fix. Do NOT modify any files. End your reply with EXACTLY one line: `VERDICT: APPROVED` if the plan is sound enough to implement, or `VERDICT: REVISE` if it still has material problems.
95
96
 
96
- ### Round 1 — fresh session (capture `thread_id`)
97
- Stream `--json` to a FILE, never pipe to `grep` — `codex exec --json | grep` deadlocks on codex-cli ≥0.137. **Always launch with `< /dev/null`** — a backgrounded `codex exec … &` without it blocks on stdin and sits at **0 CPU / 0 bytes** forever (the #1 cause of the "silent hang"; verified 2026-06-09). Background it so a **90s liveness probe** still catches a genuine sandbox deadlock.
97
+ ### Round 1 — fresh wrapper-owned session
98
+
98
99
  ```bash
99
- CODEX_TMP="/tmp/codex-$(pwd | sha1sum | cut -c1-8)"; mkdir -p "$CODEX_TMP" # run-unique per worktree cwd: STABLE across round-1+resume turns, collision-free under parallel sessions
100
- codex exec -s read-only --json -o $CODEX_TMP/verdict.txt "$(cat REVIEW_PROMPT)" \
101
- < /dev/null > $CODEX_TMP/r1.jsonl 2>/dev/null &
102
- CODEX_PID=$!
103
- sleep 90 # liveness probe (REQUIRED)
104
- if kill -0 "$CODEX_PID" 2>/dev/null; then
105
- CPU=$(ps -o time= -p "$CODEX_PID" 2>/dev/null | tr -dc '0-9:') # cumulative CPU, e.g. 00:00:00
106
- BYTES=$(wc -c < $CODEX_TMP/r1.jsonl 2>/dev/null || echo 0)
107
- if [ "${CPU:-00:00:00}" = "00:00:00" ] && [ "${BYTES:-0}" -eq 0 ]; then
108
- kill -9 "$CODEX_PID" 2>/dev/null; echo "CODEX-HUNG" # alive + 0 CPU + 0 bytes = blocked, NOT working
109
- fi
100
+ if ROUND_RESULT=$(scripts/codex-exec.sh new --profile review --mode read-only --prompt "$REVIEW_PROMPT"); then
101
+ RUN_ID=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["runId"])')
102
+ CODEX_REPORT=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["verdict"])')
103
+ else
104
+ FAILURE_RESULT=$(scripts/codex-exec.sh handle-failure --result "$ROUND_RESULT") || :
105
+ printf '%s\n' "$FAILURE_RESULT" >&2
106
+ exit 1
110
107
  fi
111
- wait "$CODEX_PID" 2>/dev/null
112
- THREAD_ID=$(grep -o '"thread_id":"[^"]*"' $CODEX_TMP/r1.jsonl | head -1 | cut -d'"' -f4)
113
108
  ```
114
- - **`CODEX-HUNG` printed** (alive + 0 CPU + 0 bytes at 90s) → **first suspect the stdin block**: confirm the launch has `< /dev/null` and retry. That fixes it in nearly every case. **NEVER `pgrep`/`kill` codex procs to "clear contention"** — that murders the user's live, unrelated codex sessions and does **not** fix a stdin hang. Only if `< /dev/null` is present and it still hangs (genuine sandbox deadlock) → **STOP Act 2**: tell the user, offer to sign off without the cross-model review or retry once. Don't touch other codex processes.
115
- - **Healthy:** CPU climbs past `00:00:00` and/or `$CODEX_TMP/r1.jsonl` grows; `THREAD_ID` parses; critique lands in `$CODEX_TMP/verdict.txt`. `2>/dev/null` hides cosmetic MCP/auth noise.
116
- - **Clean finish but no verdict file + no `THREAD_ID`** = auth/model failure → stop, tell the user.
117
109
 
118
- ### Rounds 2..MAX — resume the SAME session (Codex remembers its prior critiques)
110
+ ### Rounds 2..MAX — resume the SAME session
111
+
119
112
  ```bash
120
- # resume REJECTS -s. Force read-only via -c sandbox_mode, or Codex inherits
121
- # config.toml (possibly danger-full-access) and could WRITE files. This is the
122
- # single most important safety line in the skill — verified 2026-06-04.
123
- CODEX_TMP="/tmp/codex-$(pwd | sha1sum | cut -c1-8)"; mkdir -p "$CODEX_TMP" # run-unique per worktree cwd: STABLE across round-1+resume turns, collision-free under parallel sessions
124
- codex exec resume "$THREAD_ID" -c sandbox_mode="read-only" --json \
125
- -o $CODEX_TMP/verdict.txt \
126
- "I revised the plan. Re-review PLAN.md — check whether your prior findings are addressed and flag anything new. End with VERDICT: APPROVED or VERDICT: REVISE." \
127
- < /dev/null 2>/dev/null >/dev/null &
113
+ if ROUND_RESULT=$(scripts/codex-exec.sh resume "$RUN_ID" --prompt "I revised the plan. Re-review PLAN.md check whether your prior findings are addressed and flag anything new. End with VERDICT: APPROVED or VERDICT: REVISE."); then
114
+ CODEX_REPORT=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["verdict"])')
115
+ else
116
+ FAILURE_RESULT=$(scripts/codex-exec.sh handle-failure --result "$ROUND_RESULT" --run-id "$RUN_ID") || :
117
+ printf '%s\n' "$FAILURE_RESULT" >&2
118
+ exit 1
119
+ fi
128
120
  ```
129
- Wrap resume in the **same 90s liveness probe** (background + `wait`). Resume discards the `--json` stream, so probe on the verdict file: `BYTES=$(wc -c < $CODEX_TMP/verdict.txt)` plus the `CPU` check — `00:00:00` CPU + empty verdict at 90s → kill, treat as `CODEX-HUNG`, same STOP path as round 1. Both `codex exec` and `codex exec resume` support `--json` and `-o/--output-last-message`.
130
121
 
131
- **Overall ceiling (both rounds):** the 90s probe catches silent hangs, not long stuck runs. Cap every `codex exec` / `codex exec resume` at **10 minutes** — via Claude Code's Bash tool pass `timeout: 600000` on the tool call (the default 2-minute tool timeout would kill real reviews mid-run); in a plain shell prefix `timeout 600` (macOS: `gtimeout 600` via coreutils). If the ceiling trips, treat it as a failed round: stop and tell the user rather than retrying blind.
122
+ The wrapper persists read-only mode and owns stdin closure, hang detection, the
123
+ overall timeout, stderr redaction, and its process group. `handle-failure`
124
+ surfaces the structured status and cleanup metadata, then the caller stops
125
+ before report handling. A surfaced `HUNG` returns to the user for the choice to
126
+ retry once with a fresh run or sign off without cross-model review. Never
127
+ inspect, signal, or kill foreign Codex processes.
128
+
129
+ Separately, cancellation or a decision to stop orchestration after an OK round
130
+ but before normal finalize must abort the known run:
131
+
132
+ ```bash
133
+ scripts/codex-exec.sh abort "$RUN_ID"
134
+ ```
132
135
 
133
136
  ### Each round, after Codex returns
134
- 1. Read `$CODEX_TMP/verdict.txt`; append to `LOG_FILE`: `## Round <n> — Codex` + the full critique.
137
+ 1. Read `CODEX_REPORT`; append to `LOG_FILE`: `## Round <n> — Codex` + the full critique.
135
138
  2. Grep the last line for the verdict:
136
139
  - `VERDICT: APPROVED` → break to Resolution (converged).
137
140
  - `VERDICT: REVISE` → Claude decides **what's actually worth acting on** (Claude is final arbiter — Codex advises, doesn't command). Revise `PLAN_FILE`. Append `### Claude's response` to `LOG_FILE`: what changed, what was rejected, why. Increment round.
138
141
  3. If round > `MAX_ROUNDS` → break to Resolution (deadlock).
139
142
 
143
+ After harvesting the final report and updating the log, delete the successful
144
+ run state:
145
+
146
+ ```bash
147
+ scripts/codex-exec.sh finalize "$RUN_ID"
148
+ ```
149
+
140
150
  ### Resolution (you sign off — final gate)
141
151
  - **APPROVED:** present the final `PLAN_FILE`, a 3-bullet summary of what the two acts improved, and the round count. Ask: *"Grilled + survived N rounds of Codex. Implement it now — Codex builds it (`/codex-build`), Claude builds it, or stop here?"* Code only on a yes. **No code is written during either act.**
142
152
  - **MAX_ROUNDS hit without APPROVED (deadlock):** do NOT fake convergence. List each unresolved point + Claude's counter-position; hand it to the user to break the tie. A flagged disagreement beats a false "approved."
@@ -149,7 +159,8 @@ If the user picks Codex: invoke the `codex-build` skill with `SPEC_FILE=PLAN.md`
149
159
 
150
160
  ## Hard rules
151
161
  - Act 1 always precedes Act 2 — don't write `PLAN.md` until the grill has actually resolved the decision tree with the user.
152
- - Codex is read-only EVERY round — `-s read-only` first call, `-c sandbox_mode="read-only"` on every resume (resume has no `-s`). It never writes.
162
+ - Codex is read-only EVERY round — establish it once through the wrapper's
163
+ `review` + `read-only` new call; every resume inherits it.
153
164
  - The loop ALWAYS terminates at `MAX_ROUNDS`.
154
165
  - Claude is final arbiter on every REVISE — incorporate good critiques, reject bad ones *with a logged reason*. Don't cave to everything (defeats the cross-model check) and don't ignore it (defeats the point).
155
166
  - Code only after the user's final sign-off.
@@ -136,6 +136,6 @@ Triggers when you **re-grill an issue that already exists in the graph** (a leaf
136
136
  2. **Check the leaf for internal contradiction** (Fix B): a body that contradicts itself ("no new UI" + "build a name field") or the anchor decision → **no execute**. Likewise a leaf that says *"final cut depends on #X"* via `<!-- final-cut-depends-on: #X -->` where **#X is closed** without resolving the cut.
137
137
  3. **On drift/contradiction:** update the affected issue(s), re-stamp `plan_revision`, set the correct bucket. An internal contradiction → set the leaf to **HITL** (remove `ready-for-agent`, add the `headings.vorBau` heading — board profile `docs/agents/board-sync.md`; <project> currently `## Vor Bau zu klären`); the drift-guard then blocks a build-handoff via `target_buildable`. So the contradiction flows through existing machinery — no semantic heuristic in the hook.
138
138
  4. **Audit, non-blocking:** `python3 scripts/execute-ready-check.py --issue <n> --mode audit` → visible two-liner. The **blocking** net is the drift-guard at handoff (`.claude/hooks/drift-guard.py`).
139
- 5. **Global `-codex` variant** can't change the repo → leave a pointer note ("reconcile the issues + re-stamp plan_revision, repo-side"); real enforcement = the repo hook. **Honest bound:** the hook fires at the handoff/session boundary, not at a "grill-exit" event; a same-session global-codex grill → direct `/tdd` (no handoff) is a documented residual (global follow-up).
139
+ 5. **Global `-codex` variant** can't change the repo → leave a pointer note ("reconcile the issues + re-stamp plan_revision, repo-side"); real enforcement = the repo hook. **Honest bound:** the hook fires at the handoff/session boundary, not at a "grill-exit" event; a same-session global-codex grill → direct `/implement` (no handoff) is a documented residual (global follow-up).
140
140
 
141
141
  **Markers used here** (HTML comments, grep-able): `<!-- guard-ack: #<n> r<N> reason:<text> by-user -->` (deliberate handoff override), `<!-- final-cut-depends-on: #<n> -->`, `<!-- handoff-intent: build|grill -->`, `<!-- guard-legacy -->` (grandfathered legacy-anchor → warn not block). **Canonical table of all markers:** module docstring of `scripts/execute-ready-check.py`.
@@ -125,7 +125,7 @@ For a cross-cutting plan, run `python3 .claude/hooks/drift-guard.py --census-sta
125
125
 
126
126
  When the decision tree is resolved, the glossary/ADRs are updated, and we're aligned, **write the agreed plan to `PLAN.md`** (use the canonical terms from `CONTEXT.md`), then run Act 2:
127
127
 
128
- > **Where to write it:** `PLAN.md` + `PLAN-REVIEW-LOG.md` are per-session scratch — write them in the working directory the implementing session will actually use, and run Codex from there (`-C <dir>` on the round-1 `exec`; `exec resume` rejects both `-C` and `-s`, so run resume from that cwd and force read-only via `-c sandbox_mode="read-only"`). A project may gitignore these files, so don't rely on git to carry them across checkouts/worktrees. In worktree-based repos, create the issue worktree BEFORE this write and plan inside it.
128
+ > **Where to write it:** `PLAN.md` + `PLAN-REVIEW-LOG.md` are per-session scratch — write them in the working directory the implementing session will actually use, and invoke the wrapper from that directory. A project may gitignore these files, so don't rely on git to carry them across checkouts/worktrees. In worktree-based repos, create the issue worktree BEFORE this write and plan inside it.
129
129
 
130
130
  ```markdown
131
131
  # Plan: <task>
@@ -160,8 +160,9 @@ Act 1 (grill-with-docs) complete — plan locked, CONTEXT.md/ADRs updated. MAX_R
160
160
  Hand the locked plan to Codex for adversarial review. Mechanics verified end-to-end (2026-06-04).
161
161
 
162
162
  ### Prerequisites
163
- - `codex --version` 0.130 (older CLIs error on the default `gpt-5.5` model).
164
- - Codex authenticated (`codex login`; ChatGPT account fine). On auth/model error, surface it — don't silently retry.
163
+ - Let `scripts/codex-exec.sh` preflight Codex before launch. It enforces the
164
+ exact tested-version allowlist, authentication, platform, and capabilities;
165
+ surface any failure rather than retrying silently.
165
166
  - Do NOT pin `-m` (config default is used; `gpt-5.x-codex` variants 400 on ChatGPT-account auth).
166
167
  - **Echo the active model before Round 1** so the user can confirm: read the `model` line from `~/.codex/config.toml` (absent = "CLI default"); state it alongside the resolved tunables. If the user objects, stop before burning a round.
167
168
 
@@ -177,48 +178,57 @@ Invoked with e.g. `rounds=3` → use it. Echo resolved values first.
177
178
  ### Review prompt (each round)
178
179
  > You are an adversarial reviewer for an implementation plan. Be skeptical and specific — your job is to find what breaks, not to be agreeable. Read the plan at `PLAN.md` (and `CONTEXT.md`/ADRs for the domain language) and any repo files you need (you are read-only). Identify concrete flaws: security holes, race conditions, missing edge cases, schema conflicts, domain-language mismatches, wrong assumptions, observability gaps, simpler alternatives. For each, give a one-line fix. Do NOT modify any files. End with EXACTLY one line: `VERDICT: APPROVED` or `VERDICT: REVISE`.
179
180
 
180
- ### Round 1 — fresh session (capture `thread_id`)
181
- Stream `--json` to a FILE, never pipe to `grep` — `codex exec --json | grep` deadlocks on codex-cli ≥0.137. **Always launch with `< /dev/null`** — a backgrounded `codex exec … &` without it blocks on stdin and sits at **0 CPU / 0 bytes** forever (the #1 cause of the "silent hang"; verified 2026-06-09). Launch in the background so a **90s liveness probe** still catches a genuine sandbox deadlock.
181
+ ### Round 1 — fresh wrapper-owned session
182
+
182
183
  ```bash
183
- CODEX_TMP="/tmp/codex-$(pwd | sha1sum | cut -c1-8)"; mkdir -p "$CODEX_TMP" # run-unique per worktree cwd: STABLE across round-1+resume turns, collision-free under parallel sessions
184
- codex exec -s read-only --json -o $CODEX_TMP/verdict.txt "$(cat REVIEW_PROMPT)" \
185
- < /dev/null > $CODEX_TMP/r1.jsonl 2>/dev/null &
186
- CODEX_PID=$!
187
- sleep 90 # liveness probe (REQUIRED)
188
- if kill -0 "$CODEX_PID" 2>/dev/null; then
189
- CPU=$(ps -o time= -p "$CODEX_PID" 2>/dev/null | tr -dc '0-9:') # cumulative CPU, e.g. 00:00:00
190
- BYTES=$(wc -c < $CODEX_TMP/r1.jsonl 2>/dev/null || echo 0)
191
- if [ "${CPU:-00:00:00}" = "00:00:00" ] && [ "${BYTES:-0}" -eq 0 ]; then
192
- kill -9 "$CODEX_PID" 2>/dev/null; echo "CODEX-HUNG" # alive + 0 CPU + 0 bytes = blocked, NOT working
193
- fi
184
+ if ROUND_RESULT=$(scripts/codex-exec.sh new --profile review --mode read-only --prompt "$REVIEW_PROMPT"); then
185
+ RUN_ID=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["runId"])')
186
+ CODEX_REPORT=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["verdict"])')
187
+ else
188
+ FAILURE_RESULT=$(scripts/codex-exec.sh handle-failure --result "$ROUND_RESULT") || :
189
+ printf '%s\n' "$FAILURE_RESULT" >&2
190
+ exit 1
194
191
  fi
195
- wait "$CODEX_PID" 2>/dev/null
196
- THREAD_ID=$(grep -o '"thread_id":"[^"]*"' $CODEX_TMP/r1.jsonl | head -1 | cut -d'"' -f4)
197
192
  ```
198
- - **`CODEX-HUNG` printed** (alive + 0 CPU + 0 bytes at 90s) → **first suspect the stdin block**: confirm the launch has `< /dev/null` and retry. That fixes it in nearly every case (verified 2026-06-09). **NEVER `pgrep`/`kill` codex procs to "clear contention"** — that murders the user's live, unrelated codex sessions and does **not** fix a stdin hang. If `< /dev/null` is already present and it still hangs (genuine sandbox deadlock) → **STOP Act 2**: append the hang to `LOG_FILE`, tell the user, and offer to (a) proceed to sign-off **without** the cross-model review, or (b) retry once more. Do **not** keep waiting minutes, and do **not** touch other codex processes.
199
- - **Healthy:** CPU climbs past `00:00:00` and/or `$CODEX_TMP/r1.jsonl` grows; `THREAD_ID` parses; critique lands in `$CODEX_TMP/verdict.txt`.
200
- - **Clean finish but no verdict file + no `THREAD_ID`** = auth/model failure → stop, tell the user. `2>/dev/null` hides cosmetic MCP/auth noise.
201
193
 
202
194
  ### Rounds 2..MAX — resume SAME session
195
+
203
196
  ```bash
204
- # resume REJECTS -s. Force read-only via -c sandbox_mode, or Codex inherits
205
- # config.toml (possibly danger-full-access) and could WRITE files. Critical
206
- # safety line — verified 2026-06-04.
207
- CODEX_TMP="/tmp/codex-$(pwd | sha1sum | cut -c1-8)"; mkdir -p "$CODEX_TMP" # run-unique per worktree cwd: STABLE across round-1+resume turns, collision-free under parallel sessions
208
- codex exec resume "$THREAD_ID" -c sandbox_mode="read-only" --json \
209
- -o $CODEX_TMP/verdict.txt \
210
- "I revised the plan. Re-review PLAN.md — check prior findings + flag anything new. End with VERDICT: APPROVED or VERDICT: REVISE." \
211
- < /dev/null 2>/dev/null >/dev/null &
197
+ if ROUND_RESULT=$(scripts/codex-exec.sh resume "$RUN_ID" --prompt "I revised the plan. Re-review PLAN.md check prior findings + flag anything new. End with VERDICT: APPROVED or VERDICT: REVISE."); then
198
+ CODEX_REPORT=$(printf '%s\n' "$ROUND_RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin)["verdict"])')
199
+ else
200
+ FAILURE_RESULT=$(scripts/codex-exec.sh handle-failure --result "$ROUND_RESULT" --run-id "$RUN_ID") || :
201
+ printf '%s\n' "$FAILURE_RESULT" >&2
202
+ exit 1
203
+ fi
212
204
  ```
213
- Wrap resume in the **same 90s liveness probe** (background + `wait`). Resume discards the `--json` stream, so probe on the verdict file instead: `BYTES=$(wc -c < $CODEX_TMP/verdict.txt)` plus the `CPU` check — `00:00:00` CPU + empty verdict at 90s → kill, treat as `CODEX-HUNG`, same STOP path as round 1.
214
205
 
215
- **Overall ceiling (both rounds):** the 90s probe catches silent hangs, not long stuck runs. Cap every `codex exec` / `codex exec resume` at **10 minutes** — via Claude Code's Bash tool pass `timeout: 600000` on the tool call (the default 2-minute tool timeout would kill real reviews mid-run); in a plain shell prefix `timeout 600` (macOS: `gtimeout 600` via coreutils). If the ceiling trips, treat it as a failed round: stop and tell the user rather than retrying blind.
206
+ The wrapper persists read-only mode and owns stdin closure, hang detection, the
207
+ overall timeout, stderr redaction, and its process group. `handle-failure`
208
+ surfaces the structured status and cleanup metadata for `LOG_FILE`, then the
209
+ caller stops before report handling. A surfaced `HUNG` returns to the user for
210
+ the choice to retry once with a fresh run or proceed without cross-model
211
+ review. Never inspect, signal, or kill foreign Codex processes.
212
+
213
+ Separately, cancellation or a decision to stop orchestration after an OK round
214
+ but before normal finalize must abort the known run:
215
+
216
+ ```bash
217
+ scripts/codex-exec.sh abort "$RUN_ID"
218
+ ```
216
219
 
217
220
  ### Each round
218
- 1. Read verdict file; append `## Round <n> — Codex` + critique to `LOG_FILE`.
221
+ 1. Read `CODEX_REPORT`; append `## Round <n> — Codex` + critique to `LOG_FILE`.
219
222
  2. Last line verdict: `APPROVED` → Resolution (converged); `REVISE` → Claude decides what's worth acting on (final arbiter), revise `PLAN_FILE`, append `### Claude's response` (what changed/rejected + why), increment.
220
223
  3. round > `MAX_ROUNDS` → Resolution (deadlock).
221
224
 
225
+ After harvesting the final report and updating the log, delete the successful
226
+ run state:
227
+
228
+ ```bash
229
+ scripts/codex-exec.sh finalize "$RUN_ID"
230
+ ```
231
+
222
232
  ### Resolution (you sign off)
223
233
  - **APPROVED:** present final plan + 3-bullet summary of what the two acts improved + round count. Ask: implement now — Codex builds it (`/codex-build`), Claude builds it, or stop? No code during either act.
224
234
  - **Deadlock (cap hit, no APPROVED):** list unresolved points + Claude's counter-position; hand to user. Don't fake convergence.
@@ -228,9 +238,11 @@ Wrap resume in the **same 90s liveness probe** (background + `wait`). Resume dis
228
238
 
229
239
  ## Hard rules
230
240
  - Act 1 precedes Act 2. `CONTEXT.md` stays a glossary only — no implementation details.
231
- - Codex read-only EVERY round (`-s read-only` first, `-c sandbox_mode="read-only"` on resume — resume has no `-s`). Never writes.
241
+ - Codex is read-only EVERY round establish it once through the wrapper's
242
+ `review` + `read-only` new call; every resume inherits it.
232
243
  - Loop ALWAYS terminates at `MAX_ROUNDS`. Claude is final arbiter on REVISE (reject with logged reason). Code only after sign-off. `LOG_FILE` is the deliverable.
233
- - EVERY codex round runs behind the **90s liveness probe** (background + CPU/output check). Never let a silent codex hang burn minutes — kill at 90s if 0 CPU + 0 output, surface it, give the user the proceed-without / retry choice.
244
+ - A `HUNG` wrapper result always returns to the user for the proceed-without or
245
+ retry-once choice.
234
246
 
235
247
  ## What NOT to do
236
248
  - Don't review already-written code (`/codex:review`). Don't pin `-codex` variants on ChatGPT auth. Don't let Codex edit files. Don't skip Act 1.
@@ -40,6 +40,18 @@ release contain the same artifact.
40
40
  conflict manually; never auto-merge, delete a local edit, or silently choose
41
41
  the incoming copy.
42
42
 
43
+ For each conflicted kit-shipped file, always ask the user whether the local
44
+ edit is a generic improvement or project-specific; never decide or act
45
+ automatically. For a generic improvement, offer to file an issue in the
46
+ public kit repository and keep the local edit in place as a bridge until a
47
+ kit release containing the improvement lands. Before running
48
+ `gh issue create --repo <owner>/agent-workflow-kit`, show a sanitized preview
49
+ of the exact title and body with consumer identifiers and secrets stripped,
50
+ then require the user's explicit approval. The consumer user does not need
51
+ to be a kit maintainer. For a project-specific edit, recommend
52
+ `npx @ikon85/agent-workflow-kit@latest own <path>` so future updates treat
53
+ that path as consumer-owned.
54
+
43
55
  4. If a candidate is interrupted, discard its reported stage directory or
44
56
  resume the transaction through the update API's `resumeFrom` option. Do not
45
57
  copy staged files into the consumer by hand.
@@ -7,7 +7,7 @@ description: >-
7
7
  delegates wave-landing responsibility to you), "ultracode diese Welle / diesen
8
8
  Cluster", or a wave-anchor issue (a cluster/umbrella issue with file-disjoint
9
9
  sub-issues whose specs are already locked) handed over to land. NOT for a single
10
- slice (just `tdd` it), NOT for finding/clustering a wave (that's `board-to-waves`),
10
+ slice (just `implement` it), NOT for finding/clustering a wave (that's `board-to-waves`),
11
11
  NOT for planning specs (that's `grill-with-docs`/`to-issues`).
12
12
  ---
13
13
 
@@ -48,6 +48,10 @@ you must NOT paraphrase.
48
48
  - **Plan-level error** (integration/verify reveals a wrong LOCKED decision, not a
49
49
  slice bug): STOP the wave. No improvised redesign AFK — keep worktrees intact,
50
50
  report findings + options.
51
+ - **On ANY wave STOP/abort:** if this run planted the active-wave claim, remove
52
+ exactly that claim as part of shutdown. Never delete a claim marker observed
53
+ during a preflight collision, nor any sibling/foreign wave marker — those are
54
+ owned by another run. A stale marker owned by this run would block a safe retry.
51
55
  - **Routing = one axis: how expensive is a wrong result to catch?** Mechanically
52
56
  caught (test/screenshot/lint) → default tier at medium/low effort; plausible-but-
53
57
  wrong / subtle logic / architecture → top tier at high effort + main-thread
@@ -72,19 +76,30 @@ you must NOT paraphrase.
72
76
  **once** that `/setup-workflow` plus project maintenance fill the layer (the
73
77
  commands/tunnel/login can't be guessed). Never treat an empty heading as a
74
78
  verify recipe.
75
- 3. **Wave worktree**: reuse the planning worktree (never re-create; the handoff
79
+ 3. **Preflight refuse a wave already in flight, otherwise claim it.** Before
80
+ dispatch, inspect all three same-machine collision signals: **(a)** an existing
81
+ `wave-active/<anchor>` tag; **(b)** any slice branch ahead of the wave's current
82
+ base (`git rev-list --count <base>..<slice-branch>` > 0); **(c)** uncommitted
83
+ changes in any slice worktree (`git -C <worktree> status --porcelain` non-empty).
84
+ A hit not created by this run means another session may be building the wave:
85
+ **STOP**, report the exact tag/branch/worktree, and do not touch it. If clean,
86
+ record that this run owns the claim and plant a LOCAL annotated tag:
87
+ `git tag -a wave-active/<anchor> -m "orchestrating since <UTC timestamp>;
88
+ slices: <slice-branches>"`. It is local coordination state — never push it.
89
+ 4. **Wave worktree**: reuse the planning worktree (never re-create; the handoff
76
90
  points there). Bring its branch to current `main`:
77
91
  `git -C <wave> merge --ff-only origin/main` (if your repo guards destructive
78
92
  git, ff-merge is the safe path — not `reset --hard`). Install dependencies with
79
93
  your package manager after (the lockfile may have moved). A gitignored plan doc
80
94
  survives the merge.
81
- 4. **Run project setup steps (`§Setup`)** the later verify needs — e.g. a DB
95
+ 5. **Run project setup steps (`§Setup`)** the later verify needs — e.g. a DB
82
96
  tunnel or service the live-verify depends on. Absent layer → start whatever your
83
97
  live-verify environment requires before Phase 4.
84
98
 
85
99
  **Done when:** anchor + every sub-issue + plan read · project layer probed
86
- (filled → project recipe; stub/absent → generic + one-time warning) · wave branch
87
- ff'd to `origin/main` + deps installed · project setup steps running.
100
+ (filled → project recipe; stub/absent → generic + one-time warning) · preflight
101
+ clean + this run's local claim planted · wave branch ff'd to `origin/main` + deps
102
+ installed · project setup steps running.
88
103
 
89
104
  ## Phase 1 — Disjointness recon (the load-bearing step)
90
105
 
@@ -116,6 +131,13 @@ Zero merge conflicts later depends entirely on getting this right.
116
131
  "X already exists in `<file>` — do NOT add it, consume only." (Real case: all 14
117
132
  sub-issues claimed the same registry adds + 4 contradictions — hub expanded to
118
133
  own all 20 keys, batch merged conflict-free.)
134
+ - **Retirement slices require a valid topological deletion order.** Before
135
+ dispatching slices that delete a legacy cluster, map every to-delete module's
136
+ production importers and build the cluster's internal import graph. Order the
137
+ deletions so no pending slice imports a module already removed; zero remaining
138
+ production importers is the behavior-neutral proof. If mutually dependent
139
+ deletions form a cycle, separate each-slice-green steps are impossible: combine
140
+ the whole cycle into ONE atomic slice instead of landing dangling imports.
119
141
 
120
142
  **Done when:** FILE→SLICES table exists · every ≥2-slice file has exactly ONE
121
143
  owning slice · disjoint waves cut in dependency order · every dependent contract
@@ -233,15 +255,19 @@ checks pass · console 0/0 · DB outcome value compared.
233
255
  - **`Closes #N` needs the keyword before EACH issue, one per line** — `Closes #a,
234
256
  #b` only closes the first. Anchor → `Part of #<anchor>`, never `closes`
235
257
  (premature close).
236
- - **Anchor tracker: `python3 scripts/board-sync.py anchor-sync <anchor#>`** — first
237
- `--dry-run`, review the diff, then write; gate symbol + stable cells of freshly
238
- appended rows by hand. Mandatory at EVERY slice event: PR-create AND merge.
258
+ - **Anchor tracker sync is mandatory at EVERY slice event (PR-create AND merge).**
259
+ Use the project-layer command from `§Landing`: dry-run first, review the diff,
260
+ then write; preserve gate symbols and stable cells of freshly appended rows.
261
+ Absent a filled layer, use the tracker's native parent/table reconciliation.
239
262
  - **Stacked follow-up PRs** that build on the unmerged wave: base on the **wave
240
- branch** (not main) the platform auto-retargets them when the wave PR merges.
241
- Note the merge order in the body.
242
- - New issues via `scripts/board-sync.py` (never bare `gh issue create`); write
243
- multi-paragraph PR/issue bodies via `--body-file` (an inline body with backticks
244
- can crash the shell).
263
+ branch** (not main) and note the merge order in every PR body. **Do NOT rely on
264
+ auto-retarget:** deleting the merged base branch can close its stacked child.
265
+ Either merge the child before deleting the base, or expect the close and open a
266
+ FRESH PR from the child's still-existing head branch against the final base.
267
+ Keep any deploy/release/manual gate in the documented merge order.
268
+ - New issues go through the project-layer board command (`§Landing`; never a bare
269
+ tracker-create call that skips the board). Write multi-paragraph bodies through
270
+ a body file so shell metacharacters cannot alter them.
245
271
 
246
272
  **Done when:** PR(s) open with correct `Closes`/`Part of` lines · anchor-sync
247
273
  written · merge order documented.
@@ -251,19 +277,40 @@ written · merge order documented.
251
277
  - Stop the dev server(s) you started, by port (`lsof -ti:<port> | xargs kill` —
252
278
  your own processes, targeted by the worktree's assigned ports, never blind).
253
279
  Remove temp verify scripts (a login helper, DB-check scripts).
280
+ - **Remove only this run's claim marker.** If this run planted
281
+ `wave-active/<anchor>`, delete that exact local tag after success or abort. Never
282
+ delete a claim marker observed during a preflight collision or any other
283
+ `wave-active/*` marker; ownership, not a broad pattern, authorizes cleanup.
254
284
  - **Before removing any slice worktree, read its `ANNAHMEN.md`** (an assumptions
255
285
  log, gitignored at worktree-root) and propagate each build-time assumption marker
256
286
  to the sibling issue it carries. A hand-driven multi-PR / migration landing does
257
287
  NOT run `wrapup`'s assumption-propagation step — this is the only place it
258
288
  happens; `worktree remove` deletes the log.
259
- - **Post-merge:** run `anchor-sync` again; verify every leaf issue actually closed
260
- (the same checks `wrapup` runs, by hand when landing outside `wrapup`). The
261
- anchor closes manually a parent is not auto-closed on sub-issue completion.
262
- - A skill edited during the wave run `codex-adapter-sync` (lives in
263
- `.agents/skills/`) in the SAME PR the mirror-presence-parity lint is a
264
- pre-PR gate and blocks a dual-surface skill PR without its mirror.
289
+ - **Post-merge completion sync:** use `§Landing` to reconcile the anchor again and
290
+ verify every leaf actually closed. Then read the anchor's `Closing Conditions`,
291
+ `Done when`, and acceptance criteria and make an explicit closure decision:
292
+ - **No open manual gate:** close the anchor, set its project completion status to
293
+ the configured done role, and re-read the board item to verify both states.
294
+ Closing the tracker issue alone is not proof that its workflow field changed.
295
+ - **Open manual gate:** ask the user in the main thread, naming the exact gate and
296
+ condition. Confirmation follows the close/status/verify path above; otherwise
297
+ leave the anchor open and add exactly one completion marker explaining the
298
+ remaining gate and close condition.
299
+ - **Program propagation:** resolve the anchor's native parent with the
300
+ project-layer command from `§Landing`. If the parent is a Program-PRD, run the
301
+ project-layer program sync after the anchor decision. On closure, set the
302
+ anchor's completion status first so the program can observe the completed wave;
303
+ run program sync again after close even if landing ran it earlier. If a manual
304
+ gate remains open, propagation may refresh the program but must not claim wave
305
+ completion. Absent a filled layer, use equivalent tracker-native parent lookup,
306
+ completion-field update, re-read, and program propagation commands.
307
+ - A skill edited during the wave → sync its dual-surface mirror in the SAME PR
308
+ using the tool named by `§Landing` when present; mirror parity remains a pre-PR
309
+ gate.
265
310
  - Leave slice worktrees for the user to inspect, or note they're
266
311
  post-merge-removable.
267
312
 
268
- **Done when:** no orphan process · ANNAHMEN propagated · anchor reconciled + leaf
269
- closes verified · final report lists landed/pulled slices as **X of Y**.
313
+ **Done when:** no orphan process · this run's claim removed · ANNAHMEN propagated ·
314
+ anchor reconciled + leaf closes verified · anchor closure decided and documented ·
315
+ Program-PRD propagation completed or explicitly skipped · final report lists
316
+ landed/pulled slices as **X of Y**.