Prepare subagent logs and heartbeat
LOG_DIR="/tmp/codex-subagent-logs/$(basename "$PWD")"
HEARTBEAT_SECONDS=60
SUBAGENT_TIMEOUT_SECONDS=7200
mkdir -p "${LOG_DIR}"
SKETCH_LOG="${LOG_DIR}/plan-sketch.log"
WRITE_LOG="${LOG_DIR}/plan-write.log"
CRITIQUE_LOG="${LOG_DIR}/plan-critique.log"
SIMPLIFY_LOG="${LOG_DIR}/simplify.log"
DEDUP_LOG="${LOG_DIR}/dedup.log"
REVIEW_LOG="${LOG_DIR}/code-review.log"
: > "${SKETCH_LOG}"
: > "${WRITE_LOG}"
: > "${CRITIQUE_LOG}"
: > "${SIMPLIFY_LOG}"
: > "${DEDUP_LOG}"
: > "${REVIEW_LOG}"
Resolve installed skill directories (so the wrapper works from any repo):
resolve_skill_dir() {
local name="$1"
local repo_root=""
repo_root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
local candidates=(
"$repo_root/.agents/skills/$name"
"$repo_root/.claude/skills/$name"
"$HOME/.agents/skills/$name"
"$HOME/.codex/skills/$name"
"$HOME/.claude/skills/$name"
)
for d in "${candidates[@]}"; do
if [[ -d "$d" ]]; then
echo "$d"
return 0
fi
done
echo "Error: skill '$name' not found in repo-scoped or user-scoped skill dirs." >&2
return 1
}
BESIMPLE_BROCCOLI_BLIND_SKILL_DIR="$(resolve_skill_dir besimple-broccoli-blind)"
PLAN_SKETCH_SKILL_DIR="$(resolve_skill_dir plan-sketch)"
PLAN_WRITE_SKILL_DIR="$(resolve_skill_dir plan-write)"
PLAN_CRITIQUE_LOOP_SKILL_DIR="$(resolve_skill_dir plan-critique-loop)"
SIMPLIFY_SKILL_DIR="$(resolve_skill_dir claude-simplify-wrapper)"
DEDUP_SKILL_DIR="$(resolve_skill_dir dedup)"
CODE_REVIEW_LOOP_SKILL_DIR="$(resolve_skill_dir code-review-loop)"
Run plan-sketch and auto-select recommended options
SKETCH_DOC=$(python3 "$PLAN_SKETCH_SKILL_DIR/scripts/run_plan_sketch.py" --idea-file "${IDEA_FILE}" --output "${LOG_DIR}/sketch.md" --timeout "${SUBAGENT_TIMEOUT_SECONDS}" --progress-log "${SKETCH_LOG}" --heartbeat-seconds "${HEARTBEAT_SECONDS}")
Extract the last user-questions block:
QUESTIONS_BLOCK=$(awk '
/^BEGIN_USER_QUESTIONS$/ {in_block=1; block=""; next}
/^END_USER_QUESTIONS$/ {in_block=0; last=block; next}
in_block {block = block $0 ORS}
END {printf "%s", last}
' "${SKETCH_LOG}")
Auto-pick recommended options by reading QUESTIONS_BLOCK directly in the LLM context (no shell/regex parsing):
- Set
AUTO_SELECTIONS to a comma-separated list of all labels whose option text ends with (Recommended) (for example: 1a, 2c).
- Do not compute
AUTO_SELECTIONS with awk, jq, or python.
- If no recommended options are present, continue to empty feedback.
Save synthetic feedback:
USER_FEEDBACK_FILE="${LOG_DIR}/user-feedback.md"
cat > "${USER_FEEDBACK_FILE}" <<'FEEDBACK'