feat(mux-loop): redesign role CLI flags with --creator and --planner, drop --target-agent

- Replace '--target-agent' with mandatory '--creator <session>' flag
- Add explicit rejection error for legacy '--target-agent'
- Add '--planner <session>' flag with fail-fast check when '--plan' is missing
- Implement 2-branch session validation ('is not registered' vs 'is not running')
- Update in-repo references in hooks, SKILL.md, INSTALL.md, and tests
- Add tests/test_loop_cli.py with 9 unit/contract tests
This commit is contained in:
2026-08-26 14:03:20 +09:00
parent d56f60bbc6
commit 87b4501bbf
8 changed files with 210 additions and 19 deletions
@@ -31,12 +31,15 @@ CLEANUP=false
TARGET_AGENT=""
TASK=""
REVIEWER_LIST=""
PLANNER_SESSION_OVERRIDE=""
# Print usage instructions
usage() {
echo "Usage: $0 [options] --target-agent <agent-session-name> --task <goal-text>"
echo "Usage: $0 [options] --creator <agent-session-name> --task <goal-text>"
echo "Options:"
echo " --creator <name> Creator session that implements the task (required)"
echo " --plan Enable Planner agent intervention & design phase"
echo " --planner <name> Planner session (requires --plan; default: auto-resolve)"
echo " --plan-talk N Planner-Creator discussion limit turns (default: 1)"
echo " --reviewer \"A,B\" Targeted reviewer session name list (comma-separated)"
echo " --all-reviewer Enforce PASS verdict from all active reviewer sessions"
@@ -73,7 +76,12 @@ while [[ "$#" -gt 0 ]]; do
MAX_REBUT="$2"; shift 2 ;;
--verbose) VERBOSE=true; shift ;;
--cleanup) CLEANUP=true; shift ;;
--target-agent) TARGET_AGENT="$2"; shift 2 ;;
--creator) TARGET_AGENT="$2"; shift 2 ;;
--target-agent)
echo "ERROR: --target-agent was removed. Use --creator <session> instead." >&2
exit 1
;;
--planner) PLANNER_SESSION_OVERRIDE="$2"; shift 2 ;;
--task) TASK="$2"; shift 2 ;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; usage ;;
@@ -85,10 +93,17 @@ done
REBUT_TOTAL_BUDGET=$((MAX_REBUT * MAX_LOOP))
if [ -z "$TARGET_AGENT" ] || [ -z "$TASK" ]; then
echo "ERROR: --target-agent and --task are mandatory fields."
echo "ERROR: --creator and --task are mandatory fields." >&2
usage
fi
if [ -n "${PLANNER_SESSION_OVERRIDE:-}" ] && [ "$PLAN_MODE" = false ]; then
echo "ERROR: --planner was specified without --plan." >&2
echo "To enable planning, include the --plan flag:" >&2
echo " run_loop.sh --creator <creator> --plan --planner <planner> --task \"...\"" >&2
exit 1
fi
# --- B-13 Stage 2: freeze the runtime before the loop can be edited under us ---
# bash keeps reading a running script from disk by byte offset, so a worker that
# edits .agents/skills/ mid-loop can break this very file (measured: even a valid
@@ -351,15 +366,35 @@ elif [ "$TARGET_STATUS" != "running" ]; then
exit 1
fi
PLANNER_SESSION=$(resolve_planner_session)
log_info "Resolved Planner session: $PLANNER_SESSION"
if [ "$PLAN_MODE" = true ]; then
if [ -z "$PLANNER_SESSION" ]; then
if [ -n "${PLANNER_SESSION_OVERRIDE:-}" ]; then
# Explicit --planner skips auto-resolve. Pre-freeze already required --plan.
PLANNER_SESSION="$PLANNER_SESSION_OVERRIDE"
PLANNER_STATUS=$(MAM_STATE_JSON="$(load_state_json)" TARGET="$PLANNER_SESSION" python3 -c "
import os, json
d = json.loads(os.environ.get('MAM_STATE_JSON', '{}'))
target = os.environ.get('TARGET')
status = ''
for s in d.get('herdr_sessions', []):
if s.get('name') == target:
status = s.get('status')
break
print(status)
")
if [ -z "$PLANNER_STATUS" ]; then
log_error "Specified planner session '$PLANNER_SESSION' is not registered in the session registry."
exit 1
elif [ "$PLANNER_STATUS" != "running" ]; then
log_error "Specified planner session '$PLANNER_SESSION' is not running (current status: '$PLANNER_STATUS')."
exit 1
fi
else
PLANNER_SESSION=$(resolve_planner_session)
if [ "$PLAN_MODE" = true ] && [ -z "$PLANNER_SESSION" ]; then
log_error "Planner mode enabled (--plan) but no running session with a 'planner' role was found."
exit 1
fi
fi
log_info "Resolved Planner session: $PLANNER_SESSION"
CURRENT_PLAN=""
CREATED_JOBS=()