refactor(sdd): platform-owned dispatch hints — shared scripts carry no Codex literals

Responds to maintainer review of this branch: the dispatch-hint lines
were hardcoded Codex strings inside shared skill tooling that every
harness runs.

The per-role hint lines now live in a platform-owned data file,
skills/using-superpowers/references/codex-dispatch.hints, and the
task-brief/review-package scripts only relay the current role's line.
The relay is suppressed when CLAUDECODE is set (Claude Code's dispatch
templates already carry model selection) and on any harness with no
hints file; unknown harnesses fail toward printing, because a silent
no-op in the environment that needs the hint is the failure mode this
mechanism exists to prevent. Printing at the moment of dispatch is
load-bearing: skill text loaded at session start does not survive
context compaction, but script output reprints every round.

codex-tools.md's SDD dispatch section shrinks to the behavioral rules
(fork_turns: "none" always; copy the printed hint verbatim; reviewer
tier never exceeds implementer tier; no effort bumps; the <=0.144
inheritance fallback) and points at the hints file for values.

Tests cover the relay path, the per-role efforts, and the new
CLAUDECODE suppression case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Drew Ritter
2026-07-22 15:31:50 -07:00
parent c97988d8d1
commit cdcadda4be
5 changed files with 101 additions and 70 deletions
@@ -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
@@ -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
@@ -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: <role>: <line printed verbatim>
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
@@ -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
+32 -17
View File
@@ -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