mirror of
https://github.com/obra/superpowers.git
synced 2026-07-23 10:44:01 +08:00
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:
@@ -13,6 +13,8 @@
|
|||||||
# does not survive context compaction, but this line is reprinted every round.
|
# does not survive context compaction, but this line is reprinted every round.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
script_dir=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
|
||||||
role=task-review
|
role=task-review
|
||||||
if [ "${1:-}" = "--role" ]; then
|
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; }
|
[ $# -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
|
shift 2
|
||||||
fi
|
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
|
case "$role" in
|
||||||
task-review) hint_role=task-reviewer; hint_effort=high ;;
|
task-review) hint_key=task-review ;;
|
||||||
re-review) hint_role=scoped-re-reviewer; hint_effort=medium ;;
|
# re-review maps onto the fix-review hints entry; the --role value itself
|
||||||
final-review) hint_role=final-reviewer; hint_effort=high ;;
|
# 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 ;;
|
*) echo "bad --role: ${role} (task-review|re-review|final-review)" >&2; exit 2 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -45,7 +47,7 @@ git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&
|
|||||||
if [ $# -eq 4 ]; then
|
if [ $# -eq 4 ]; then
|
||||||
out=$4
|
out=$4
|
||||||
else
|
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"
|
out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -64,4 +66,16 @@ fi
|
|||||||
|
|
||||||
commits=$(git rev-list --count "${base}..${head}")
|
commits=$(git rev-list --count "${base}..${head}")
|
||||||
echo "wrote ${out}: ${commits} commit(s), $(wc -c < "$out" | tr -d ' ') bytes"
|
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
|
n=$2
|
||||||
[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
|
[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; }
|
||||||
|
|
||||||
|
script_dir=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
|
||||||
if [ $# -eq 3 ]; then
|
if [ $# -eq 3 ]; then
|
||||||
out=$3
|
out=$3
|
||||||
else
|
else
|
||||||
dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan")
|
dir=$("$script_dir/sdd-workspace" "$plan")
|
||||||
out="$dir/task-${n}-brief.md"
|
out="$dir/task-${n}-brief.md"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -39,9 +41,16 @@ if [ ! -s "$out" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "wrote ${out}: $(wc -l < "$out" | tr -d ' ') lines"
|
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
|
# Platform dispatch hints ride this output because the controller reads it
|
||||||
# start does not survive context compaction, but this line reprints per task.
|
# immediately before spawning; the lines themselves are owned by the platform
|
||||||
# Model/effort values are mirrored in using-superpowers/references/codex-tools.md
|
# reference layer (using-superpowers/references/*-dispatch.hints), not this
|
||||||
# (they track Codex's spawn_agent allowlist) — update both together.
|
# script. Claude Code's dispatch templates carry model selection already, so
|
||||||
echo "dispatch (codex spawn_agent): role=implementer fork_turns=none model=gpt-5.6-terra reasoning_effort=high"
|
# 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
|
||||||
|
|||||||
11
skills/using-superpowers/references/codex-dispatch.hints
Normal file
11
skills/using-superpowers/references/codex-dispatch.hints
Normal file
@@ -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.
|
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
|
Every SDD `spawn_agent` call sets `fork_turns: "none"` — the default
|
||||||
`fork_turns: "none"`. The parameter defaults to `"all"`, which forks your
|
`"all"` forks your whole transcript into the child and refuses model
|
||||||
entire session transcript into the child — the opposite of the fresh,
|
and effort overrides.
|
||||||
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.
|
|
||||||
|
|
||||||
Before Task 1, check your `spawn_agent` tool schema for `model` and
|
If your `spawn_agent` schema has `model` and `reasoning_effort`
|
||||||
`reasoning_effort` parameters (present on Codex 0.145+).
|
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
|
Without those parameters (Codex 0.144 and earlier), children inherit
|
||||||
task-brief and review-package scripts print the exact values for each
|
your model and effort with no override — role files in
|
||||||
dispatch as a `dispatch (codex spawn_agent):` line with their output —
|
`~/.codex/agents/` do not attach to spawns either. Tell your human
|
||||||
copy that line's values onto the spawn_agent call verbatim, every time,
|
partner before starting a plan of more than a few tasks, and offer a
|
||||||
even late in a long session. The mapping they print: every SDD seat runs
|
lower-effort session instead.
|
||||||
`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.
|
|
||||||
|
|
||||||
## Environment Detection
|
## Environment Detection
|
||||||
|
|
||||||
|
|||||||
@@ -165,39 +165,54 @@ PLAN
|
|||||||
echo " got: $rp_explicit"
|
echo " got: $rp_explicit"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- dispatch hints ride the script output ---
|
# --- platform dispatch hints ride the script output (suppressed on CC) ---
|
||||||
if [[ "$brief_out" == *"dispatch (codex spawn_agent): role=implementer fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then
|
local brief_hint
|
||||||
pass "task-brief prints the implementer dispatch 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
|
else
|
||||||
fail "task-brief prints the implementer dispatch hint"
|
fail "task-brief relays the implementer dispatch hint off Claude Code"
|
||||||
echo " got: $brief_out"
|
echo " got: $brief_hint"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$rp_out" == *"dispatch (codex spawn_agent): role=task-reviewer fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then
|
local rp_hint
|
||||||
pass "review-package defaults to the task-reviewer dispatch 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
|
else
|
||||||
fail "review-package defaults to the task-reviewer dispatch hint"
|
fail "review-package relays the default-role hint off Claude Code"
|
||||||
echo " got: $rp_out"
|
echo " got: $rp_hint"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local rp_rereview
|
local rp_rereview
|
||||||
rp_rereview="$(cd "$repo" && "$SDD_SCRIPTS/review-package" --role re-review plan-a.md HEAD~1 HEAD)"
|
rp_rereview="$(cd "$repo" && env -u CLAUDECODE "$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
|
if [[ "$rp_rereview" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=medium"* ]]; then
|
||||||
pass "review-package --role re-review prints the medium-effort hint"
|
pass "review-package --role re-review relays the medium-effort hint"
|
||||||
else
|
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"
|
echo " got: $rp_rereview"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local rp_final
|
local rp_final
|
||||||
rp_final="$(cd "$repo" && "$SDD_SCRIPTS/review-package" --role final-review plan-a.md HEAD~1 HEAD)"
|
rp_final="$(cd "$repo" && env -u CLAUDECODE "$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
|
if [[ "$rp_final" == *"dispatch (spawn_agent): fork_turns=none model=gpt-5.6-terra reasoning_effort=high"* ]]; then
|
||||||
pass "review-package --role final-review prints the final-reviewer hint"
|
pass "review-package --role final-review relays the high-effort hint"
|
||||||
else
|
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"
|
echo " got: $rp_final"
|
||||||
fi
|
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
|
rc=0
|
||||||
(cd "$repo" && "$SDD_SCRIPTS/review-package" --role bogus plan-a.md HEAD~1 HEAD >/dev/null 2>&1) || rc=$?
|
(cd "$repo" && "$SDD_SCRIPTS/review-package" --role bogus plan-a.md HEAD~1 HEAD >/dev/null 2>&1) || rc=$?
|
||||||
if [[ "$rc" -eq 2 ]]; then
|
if [[ "$rc" -eq 2 ]]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user