diff --git a/skills/subagent-driven-development/scripts/review-package b/skills/subagent-driven-development/scripts/review-package index a6432e2f..b988d424 100755 --- a/skills/subagent-driven-development/scripts/review-package +++ b/skills/subagent-driven-development/scripts/review-package @@ -13,6 +13,8 @@ # does not survive context compaction, but this line is reprinted every round. set -euo pipefail +script_dir=$(cd "$(dirname "$0")" && pwd) + role=task-review if [ "${1:-}" = "--role" ]; then [ $# -ge 2 ] || { echo "usage: review-package [--role task-review|re-review|final-review] PLAN_FILE BASE HEAD [OUTFILE]" >&2; exit 2; } @@ -20,12 +22,12 @@ if [ "${1:-}" = "--role" ]; then shift 2 fi -# Model/effort values are mirrored in using-superpowers/references/codex-tools.md -# (they track Codex's spawn_agent allowlist) — update both together. case "$role" in - task-review) hint_role=task-reviewer; hint_effort=high ;; - re-review) hint_role=scoped-re-reviewer; hint_effort=medium ;; - final-review) hint_role=final-reviewer; hint_effort=high ;; + task-review) hint_key=task-review ;; + # re-review maps onto the fix-review hints entry; the --role value itself + # is renamed in the next commit. + re-review) hint_key=fix-review ;; + final-review) hint_key=final-review ;; *) echo "bad --role: ${role} (task-review|re-review|final-review)" >&2; exit 2 ;; esac @@ -45,7 +47,7 @@ git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >& if [ $# -eq 4 ]; then out=$4 else - dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan") + dir=$("$script_dir/sdd-workspace" "$plan") out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff" fi @@ -64,4 +66,16 @@ fi commits=$(git rev-list --count "${base}..${head}") echo "wrote ${out}: ${commits} commit(s), $(wc -c < "$out" | tr -d ' ') bytes" -echo "dispatch (codex spawn_agent): role=${hint_role} fork_turns=none model=gpt-5.6-terra reasoning_effort=${hint_effort}" + +# Platform dispatch hints ride this output because the controller reads it +# immediately before spawning; the lines themselves are owned by the platform +# reference layer (using-superpowers/references/*-dispatch.hints), not this +# script. Claude Code's dispatch templates carry model selection already, so +# the relay is suppressed there and on any harness without a hints file. +hints_file="$script_dir/../../using-superpowers/references/codex-dispatch.hints" +if [ -z "${CLAUDECODE:-}" ] && [ -f "$hints_file" ]; then + hint_line=$(grep "^${hint_key}:" "$hints_file" | head -1 | cut -d: -f2- | sed 's/^ *//') || true + if [ -n "$hint_line" ]; then + echo "$hint_line" + fi +fi diff --git a/skills/subagent-driven-development/scripts/task-brief b/skills/subagent-driven-development/scripts/task-brief index 814df8aa..269939c6 100755 --- a/skills/subagent-driven-development/scripts/task-brief +++ b/skills/subagent-driven-development/scripts/task-brief @@ -18,10 +18,12 @@ plan=$1 n=$2 [ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; } +script_dir=$(cd "$(dirname "$0")" && pwd) + if [ $# -eq 3 ]; then out=$3 else - dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan") + dir=$("$script_dir/sdd-workspace" "$plan") out="$dir/task-${n}-brief.md" fi @@ -39,9 +41,16 @@ if [ ! -s "$out" ]; then fi echo "wrote ${out}: $(wc -l < "$out" | tr -d ' ') lines" -# The dispatch hint rides this output because the controller reads it -# immediately before spawning the implementer; skill text loaded at session -# start does not survive context compaction, but this line reprints per task. -# Model/effort values are mirrored in using-superpowers/references/codex-tools.md -# (they track Codex's spawn_agent allowlist) — update both together. -echo "dispatch (codex spawn_agent): role=implementer fork_turns=none model=gpt-5.6-terra reasoning_effort=high" + +# Platform dispatch hints ride this output because the controller reads it +# immediately before spawning; the lines themselves are owned by the platform +# reference layer (using-superpowers/references/*-dispatch.hints), not this +# script. Claude Code's dispatch templates carry model selection already, so +# the relay is suppressed there and on any harness without a hints file. +hints_file="$script_dir/../../using-superpowers/references/codex-dispatch.hints" +if [ -z "${CLAUDECODE:-}" ] && [ -f "$hints_file" ]; then + hint_line=$(grep "^implementer:" "$hints_file" | head -1 | cut -d: -f2- | sed 's/^ *//') || true + if [ -n "$hint_line" ]; then + echo "$hint_line" + fi +fi diff --git a/skills/using-superpowers/references/codex-dispatch.hints b/skills/using-superpowers/references/codex-dispatch.hints new file mode 100644 index 00000000..e2a6008b --- /dev/null +++ b/skills/using-superpowers/references/codex-dispatch.hints @@ -0,0 +1,11 @@ +# Per-role dispatch lines for Codex spawn_agent, relayed by the +# subagent-driven-development task-brief and review-package scripts at the +# moment of dispatch (skill text loaded at session start does not survive +# context compaction; these lines reprint every round). +# Model names track Codex's spawn_agent allowlist (currently gpt-5.6-sol +# and gpt-5.6-terra) — update this file when the allowlist changes. +# Format: : +implementer: dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high +task-review: dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high +fix-review: dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=medium +final-review: dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high diff --git a/skills/using-superpowers/references/codex-tools.md b/skills/using-superpowers/references/codex-tools.md index 15fca4bd..1b4d907e 100644 --- a/skills/using-superpowers/references/codex-tools.md +++ b/skills/using-superpowers/references/codex-tools.md @@ -9,48 +9,30 @@ multi_agent = true This enables `spawn_agent`, `wait_agent`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`. When using subagent-driven-development, close reviewer subagents when their review returns. Keep each implementer subagent open until its task's review passes — the fix loop resumes the implementer — then close it. If your harness cannot send another message to a spawned agent, dispatch each fix round as a fresh implementer carrying the brief, the report file, and the findings. -## SDD dispatch: pin fork_turns and the model on every spawn +## SDD dispatch on Codex -Every `spawn_agent` call in subagent-driven-development sets -`fork_turns: "none"`. The parameter defaults to `"all"`, which forks your -entire session transcript into the child — the opposite of the fresh, -constructed context SDD requires — and a full-history fork also refuses -model and effort overrides. Never omit the parameter, and never pass -`"all"` or a turn count for an SDD dispatch. +Every SDD `spawn_agent` call sets `fork_turns: "none"` — the default +`"all"` forks your whole transcript into the child and refuses model +and effort overrides. -Before Task 1, check your `spawn_agent` tool schema for `model` and -`reasoning_effort` parameters (present on Codex 0.145+). +If your `spawn_agent` schema has `model` and `reasoning_effort` +parameters (Codex 0.145+), set both on every dispatch: task-brief and +review-package print a `dispatch:` hint line with the exact values — +copy it onto the call verbatim, every time, even late in a long +session. Those hints are the Model Selection mapping on Codex: +reviewer tier never exceeds implementer tier, no fix round gets an +effort bump, and rounds 4-5's "more capable model" means a fresh +implementer at the same tier — needing more is a BLOCKED escalation +to your human partner. Inherited frontier-tier subagents are a +measured cause of runs spinning out for hours. (Values live in +`codex-dispatch.hints` beside this file; they track the spawn_agent +model allowlist.) -**If the parameters exist**, set both explicitly on every dispatch. The -task-brief and review-package scripts print the exact values for each -dispatch as a `dispatch (codex spawn_agent):` line with their output — -copy that line's values onto the spawn_agent call verbatim, every time, -even late in a long session. The mapping they print: every SDD seat runs -`gpt-5.6-terra` — implementers and reviewers at `reasoning_effort: high`, -scoped re-reviews at `medium`. On Codex this mapping IS the Model -Selection section — including the final review, which stays on -terra/high rather than "most capable available." Never give a subagent -your session's model when you run a frontier config (sol at xhigh or -max): reviewer tier never exceeds implementer tier, and a fix round -never gets an effort bump. Rounds 4-5's "more capable model" means a -fresh implementer at the same tier; a task that genuinely needs more -than terra/high is a BLOCKED escalation to your human partner, not a -quiet tier climb. Inherited frontier-tier subagents are a measured cause -of SDD runs spinning out for hours: review seats that inherit a frontier -model at maximum effort find real-but-endless defects every round, and -fix diffs balloon instead of converging. - -The model names here track Codex's `spawn_agent` allowlist (currently -`gpt-5.6-sol` and `gpt-5.6-terra`). When the allowlist changes, update -this file and the hint lines in task-brief and review-package together. - -**If the parameters do not exist** (Codex 0.144 and earlier), every child -inherits your session's model and effort and no override is possible — -role files in `~/.codex/agents/` do not attach to spawns either. Say so -to your human partner before starting a plan of more than a few tasks, -and offer the choice: proceed with inheritance, or restart the session -at a lower effort so the whole run — controller and children — pays the -lower rate. +Without those parameters (Codex 0.144 and earlier), children inherit +your model and effort with no override — role files in +`~/.codex/agents/` do not attach to spawns either. Tell your human +partner before starting a plan of more than a few tasks, and offer a +lower-effort session instead. ## Environment Detection diff --git a/tests/claude-code/test-sdd-workspace.sh b/tests/claude-code/test-sdd-workspace.sh index 1178f340..0e322140 100755 --- a/tests/claude-code/test-sdd-workspace.sh +++ b/tests/claude-code/test-sdd-workspace.sh @@ -165,39 +165,54 @@ PLAN echo " got: $rp_explicit" fi - # --- dispatch hints ride the script output --- - if [[ "$brief_out" == *"dispatch (codex spawn_agent): role=implementer fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then - pass "task-brief prints the implementer dispatch hint" + # --- platform dispatch hints ride the script output (suppressed on CC) --- + local brief_hint + brief_hint="$(cd "$repo" && env -u CLAUDECODE "$SDD_SCRIPTS/task-brief" plan-a.md 1)" + if [[ "$brief_hint" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then + pass "task-brief relays the implementer dispatch hint off Claude Code" else - fail "task-brief prints the implementer dispatch hint" - echo " got: $brief_out" + fail "task-brief relays the implementer dispatch hint off Claude Code" + echo " got: $brief_hint" fi - if [[ "$rp_out" == *"dispatch (codex spawn_agent): role=task-reviewer fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then - pass "review-package defaults to the task-reviewer dispatch hint" + local rp_hint + rp_hint="$(cd "$repo" && env -u CLAUDECODE "$SDD_SCRIPTS/review-package" plan-a.md HEAD~1 HEAD)" + if [[ "$rp_hint" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then + pass "review-package relays the default-role hint off Claude Code" else - fail "review-package defaults to the task-reviewer dispatch hint" - echo " got: $rp_out" + fail "review-package relays the default-role hint off Claude Code" + echo " got: $rp_hint" fi local rp_rereview - rp_rereview="$(cd "$repo" && "$SDD_SCRIPTS/review-package" --role re-review plan-a.md HEAD~1 HEAD)" - if [[ "$rp_rereview" == *"role=scoped-re-reviewer fork_turns=none model=gpt-5.6-terra reasoning_effort=medium"* ]]; then - pass "review-package --role re-review prints the medium-effort hint" + rp_rereview="$(cd "$repo" && env -u CLAUDECODE "$SDD_SCRIPTS/review-package" --role re-review plan-a.md HEAD~1 HEAD)" + if [[ "$rp_rereview" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=medium"* ]]; then + pass "review-package --role re-review relays the medium-effort hint" else - fail "review-package --role re-review prints the medium-effort hint" + fail "review-package --role re-review relays the medium-effort hint" echo " got: $rp_rereview" fi local rp_final - rp_final="$(cd "$repo" && "$SDD_SCRIPTS/review-package" --role final-review plan-a.md HEAD~1 HEAD)" - if [[ "$rp_final" == *"role=final-reviewer fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then - pass "review-package --role final-review prints the final-reviewer hint" + rp_final="$(cd "$repo" && env -u CLAUDECODE "$SDD_SCRIPTS/review-package" --role final-review plan-a.md HEAD~1 HEAD)" + if [[ "$rp_final" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then + pass "review-package --role final-review relays the high-effort hint" else - fail "review-package --role final-review prints the final-reviewer hint" + fail "review-package --role final-review relays the high-effort hint" echo " got: $rp_final" fi + local brief_cc rp_cc + brief_cc="$(cd "$repo" && CLAUDECODE=1 "$SDD_SCRIPTS/task-brief" plan-a.md 1)" + rp_cc="$(cd "$repo" && CLAUDECODE=1 "$SDD_SCRIPTS/review-package" plan-a.md HEAD~1 HEAD)" + if [[ "$brief_cc" != *"dispatch (spawn_agent)"* && "$rp_cc" != *"dispatch (spawn_agent)"* ]]; then + pass "dispatch hints are suppressed under Claude Code (CLAUDECODE set)" + else + fail "dispatch hints are suppressed under Claude Code (CLAUDECODE set)" + echo " brief: $brief_cc" + echo " rp: $rp_cc" + fi + rc=0 (cd "$repo" && "$SDD_SCRIPTS/review-package" --role bogus plan-a.md HEAD~1 HEAD >/dev/null 2>&1) || rc=$? if [[ "$rc" -eq 2 ]]; then