@@ -583,11 +583,25 @@ if ! command -v python3 &>/dev/null; then
583583 exit 1
584584fi
585585
586- if ! command -v claude & > /dev/null; then
587- echo -e " ${RED} ERROR: claude CLI not found in PATH${NC} "
588- echo " Install: https://docs.anthropic.com/en/docs/claude-code"
589- exit 1
590- fi
586+ case " ${GAAI_DAEMON_EXECUTOR:- claude} " in
587+ claude)
588+ if ! command -v claude & > /dev/null; then
589+ echo -e " ${RED} ERROR: claude CLI not found in PATH${NC} "
590+ echo " Install: https://docs.anthropic.com/en/docs/claude-code"
591+ exit 1
592+ fi
593+ ;;
594+ codex)
595+ if ! command -v codex & > /dev/null; then
596+ echo -e " ${RED} ERROR: codex CLI not found in PATH${NC} "
597+ exit 1
598+ fi
599+ ;;
600+ * )
601+ echo -e " ${RED} ERROR: unknown GAAI_DAEMON_EXECUTOR='${GAAI_DAEMON_EXECUTOR:- } ' (expected claude or codex)${NC} "
602+ exit 1
603+ ;;
604+ esac
591605
592606if [[ ! -f " $SCHEDULER " ]]; then
593607 echo -e " ${RED} ERROR: backlog-scheduler.sh not found at $SCHEDULER ${NC} "
@@ -3223,49 +3237,53 @@ if [[ -n "\${_BINDING_JWT}" ]]; then
32233237 _MCP_HEADER_ARGS=(--header "X-GAAI-Authorized-Workspaces:\$ {_BINDING_JWT}")
32243238fi
32253239
3226- # --output-format stream-json streams NDJSON events in real-time, so:
3227- # - tee updates the log file continuously (natural heartbeat for daemon monitor)
3228- # - tail -f shows progress in real-time
3229- # Dispatch wall-clock cap: prefer gtimeout (macOS: brew install coreutils) → timeout (BSD) →
3230- # no binary = MAX_TURNS flag cap + daemon heartbeat watchdog are the liveness guards.
3240+ # --output-format stream-json / codex --json stream events in real time, so tee
3241+ # updates the log continuously (natural heartbeat for daemon monitor).
3242+ _AGENT_PROMPT="\$ {DELIVERY_PROMPT}
3243+
3244+ Deliver story: $story_id "
3245+
3246+ _TIMEOUT_PREFIX=()
32313247if command -v gtimeout &>/dev/null; then
3232- GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3233- GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3234- ANTHROPIC_BASE_URL="\$ {ANTHROPIC_BASE_URL:-}" \
3235- GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3236- GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3237- GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3238- GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3239- gtimeout "$DELIVERY_TIMEOUT " claude $CLAUDE_FLAGS "\$ {_MCP_HEADER_ARGS[@]}" -p "\$ {DELIVERY_PROMPT}
3240-
3241- Deliver story: $story_id " 2>&1 | tee -a "$delivery_log "
3242- EXIT_CODE=\$ {PIPESTATUS[0]}
3248+ _TIMEOUT_PREFIX=(gtimeout "$DELIVERY_TIMEOUT ")
32433249elif command -v timeout &>/dev/null; then
3244- GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3245- GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3246- ANTHROPIC_BASE_URL="\$ {ANTHROPIC_BASE_URL:-}" \
3247- GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3248- GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3249- GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3250- GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3251- timeout "$DELIVERY_TIMEOUT " claude $CLAUDE_FLAGS "\$ {_MCP_HEADER_ARGS[@]}" -p "\$ {DELIVERY_PROMPT}
3252-
3253- Deliver story: $story_id " 2>&1 | tee -a "$delivery_log "
3254- EXIT_CODE=\$ {PIPESTATUS[0]}
3255- else
3256- GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3257- GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3258- ANTHROPIC_BASE_URL="\$ {ANTHROPIC_BASE_URL:-}" \
3259- GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3260- GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3261- GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3262- GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3263- claude $CLAUDE_FLAGS "\$ {_MCP_HEADER_ARGS[@]}" -p "\$ {DELIVERY_PROMPT}
3264-
3265- Deliver story: $story_id " 2>&1 | tee -a "$delivery_log "
3266- EXIT_CODE=\$ {PIPESTATUS[0]}
3250+ _TIMEOUT_PREFIX=(timeout "$DELIVERY_TIMEOUT ")
32673251fi
32683252
3253+ case "\$ {GAAI_DAEMON_EXECUTOR:-claude}" in
3254+ claude)
3255+ GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3256+ GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3257+ ANTHROPIC_BASE_URL="\$ {ANTHROPIC_BASE_URL:-}" \
3258+ GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3259+ GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3260+ GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3261+ GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3262+ "\$ {_TIMEOUT_PREFIX[@]}" claude $CLAUDE_FLAGS "\$ {_MCP_HEADER_ARGS[@]}" -p "\$ {_AGENT_PROMPT}" 2>&1 | tee -a "$delivery_log "
3263+ EXIT_CODE=\$ {PIPESTATUS[0]}
3264+ ;;
3265+ codex)
3266+ _CODEX_SANDBOX="\$ {GAAI_CODEX_SANDBOX:-workspace-write}"
3267+ [[ "\$ _CODEX_SANDBOX" == "danger" ]] && _CODEX_SANDBOX="danger-full-access"
3268+ _CODEX_ARGS=(exec --json --cd "$PROJECT_DIR " --sandbox "\$ _CODEX_SANDBOX")
3269+ [[ "\$ {GAAI_CODEX_EPHEMERAL:-1}" != "0" ]] && _CODEX_ARGS+=(--ephemeral)
3270+ [[ "\$ {GAAI_CODEX_IGNORE_USER_CONFIG:-0}" == "1" ]] && _CODEX_ARGS+=(--ignore-user-config)
3271+ [[ -n "\$ {GAAI_CODEX_MODEL:-}" ]] && _CODEX_ARGS+=(--model "\$ {GAAI_CODEX_MODEL}")
3272+ GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3273+ GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3274+ GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3275+ GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3276+ GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3277+ GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3278+ "\$ {_TIMEOUT_PREFIX[@]}" codex "\$ {_CODEX_ARGS[@]}" "\$ {_AGENT_PROMPT}" 2>&1 | tee -a "$delivery_log "
3279+ EXIT_CODE=\$ {PIPESTATUS[0]}
3280+ ;;
3281+ *)
3282+ echo "ERROR: unknown GAAI_DAEMON_EXECUTOR='\$ {GAAI_DAEMON_EXECUTOR:-}'" >&2
3283+ EXIT_CODE=2
3284+ ;;
3285+ esac
3286+
32693287echo ""
32703288echo "================================================================"
32713289echo " Delivery ended: $story_id "
@@ -3898,38 +3916,52 @@ if [[ -n "\${_BINDING_JWT}" ]]; then
38983916 _MCP_HEADER_ARGS=(--header "X-GAAI-Authorized-Workspaces:\$ {_BINDING_JWT}")
38993917fi
39003918
3901- # Print mode (-p): claude processes the prompt and exits, freeing the daemon slot.
3902- # --dangerously-skip-permissions handles tool approval (required for headless).
3903- # --output-format stream-json streams NDJSON events in real-time, so:
3904- # - tee updates the log file continuously (natural heartbeat for daemon monitor)
3905- # - tail -f shows progress in real-time
3919+ # Claude remains the default executor. Codex is opt-in via GAAI_DAEMON_EXECUTOR=codex.
3920+ _AGENT_PROMPT="\$ {DELIVERY_PROMPT}
3921+
3922+ Deliver story: $story_id "
39063923
3924+ _TIMEOUT_PREFIX=()
39073925if command -v gtimeout &>/dev/null; then
3908- GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3909- GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3910- ANTHROPIC_BASE_URL="\$ {ANTHROPIC_BASE_URL:-}" \
3911- GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3912- GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3913- GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3914- GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3915- gtimeout "$DELIVERY_TIMEOUT " claude $CLAUDE_FLAGS "\$ {_MCP_HEADER_ARGS[@]}" -p "\$ {DELIVERY_PROMPT}
3916-
3917- Deliver story: $story_id " 2>&1 | tee -a "$delivery_log "
3918- EXIT_CODE=\$ {PIPESTATUS[0]}
3919- else
3920- GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3921- GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3922- ANTHROPIC_BASE_URL="\$ {ANTHROPIC_BASE_URL:-}" \
3923- GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3924- GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3925- GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3926- GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3927- claude $CLAUDE_FLAGS "\$ {_MCP_HEADER_ARGS[@]}" -p "\$ {DELIVERY_PROMPT}
3928-
3929- Deliver story: $story_id " 2>&1 | tee -a "$delivery_log "
3930- EXIT_CODE=\$ {PIPESTATUS[0]}
3926+ _TIMEOUT_PREFIX=(gtimeout "$DELIVERY_TIMEOUT ")
3927+ elif command -v timeout &>/dev/null; then
3928+ _TIMEOUT_PREFIX=(timeout "$DELIVERY_TIMEOUT ")
39313929fi
39323930
3931+ case "\$ {GAAI_DAEMON_EXECUTOR:-claude}" in
3932+ claude)
3933+ GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3934+ GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3935+ ANTHROPIC_BASE_URL="\$ {ANTHROPIC_BASE_URL:-}" \
3936+ GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3937+ GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3938+ GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3939+ GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3940+ "\$ {_TIMEOUT_PREFIX[@]}" claude $CLAUDE_FLAGS "\$ {_MCP_HEADER_ARGS[@]}" -p "\$ {_AGENT_PROMPT}" 2>&1 | tee -a "$delivery_log "
3941+ EXIT_CODE=\$ {PIPESTATUS[0]}
3942+ ;;
3943+ codex)
3944+ _CODEX_SANDBOX="\$ {GAAI_CODEX_SANDBOX:-workspace-write}"
3945+ [[ "\$ _CODEX_SANDBOX" == "danger" ]] && _CODEX_SANDBOX="danger-full-access"
3946+ _CODEX_ARGS=(exec --json --cd "$PROJECT_DIR " --sandbox "\$ _CODEX_SANDBOX")
3947+ [[ "\$ {GAAI_CODEX_EPHEMERAL:-1}" != "0" ]] && _CODEX_ARGS+=(--ephemeral)
3948+ [[ "\$ {GAAI_CODEX_IGNORE_USER_CONFIG:-0}" == "1" ]] && _CODEX_ARGS+=(--ignore-user-config)
3949+ [[ -n "\$ {GAAI_CODEX_MODEL:-}" ]] && _CODEX_ARGS+=(--model "\$ {GAAI_CODEX_MODEL}")
3950+ GAAI_WORKSPACE_ID="\$ {GAAI_WORKSPACE_ID:-}" \
3951+ GAAI_ORG_ID="\$ {GAAI_ORG_ID:-}" \
3952+ GAAI_IMPL_BASE_URL="\$ {GAAI_IMPL_BASE_URL:-}" \
3953+ GAAI_IMPL_AUTH_TOKEN="\$ {GAAI_IMPL_AUTH_TOKEN:-}" \
3954+ GAAI_IMPL_MODEL="\$ {GAAI_IMPL_MODEL:-}" \
3955+ GAAI_DELIVERY_LOG_FILE="$LOG_DIR /${story_id} .log" \
3956+ "\$ {_TIMEOUT_PREFIX[@]}" codex "\$ {_CODEX_ARGS[@]}" "\$ {_AGENT_PROMPT}" 2>&1 | tee -a "$delivery_log "
3957+ EXIT_CODE=\$ {PIPESTATUS[0]}
3958+ ;;
3959+ *)
3960+ echo "ERROR: unknown GAAI_DAEMON_EXECUTOR='\$ {GAAI_DAEMON_EXECUTOR:-}'" >&2
3961+ EXIT_CODE=2
3962+ ;;
3963+ esac
3964+
39333965# ── Agent exit signal (DEC-72 wrapper-side audit trail) ─────────────────────
39343966EXIT_TS=\$ (date +%s)
39353967DURATION_MS=\$ (( (EXIT_TS - PREFLIGHT_TS) * 1000 ))
@@ -4237,11 +4269,15 @@ shutdown() {
42374269trap shutdown SIGINT SIGTERM
42384270
42394271# ── Save config for monitor ──────────────────────────────────────────────
4272+ DISPLAY_MODEL=" $CLAUDE_MODEL "
4273+ if [[ " ${GAAI_DAEMON_EXECUTOR:- claude} " == " codex" ]]; then
4274+ DISPLAY_MODEL=" ${GAAI_CODEX_MODEL:- codex} "
4275+ fi
42404276cat > " $LOCK_DIR /.daemon-config" << EOF
42414277BRANCH="$TARGET_BRANCH "
42424278INTERVAL="$POLL_INTERVAL "
42434279CONCURRENT="$MAX_CONCURRENT "
4244- MODEL="$CLAUDE_MODEL "
4280+ MODEL="$DISPLAY_MODEL "
42454281LAUNCHER="$LAUNCHER "
42464282SKIP_PERMS="$SKIP_PERMISSIONS "
42474283MAX_TURNS="$MAX_TURNS "
0 commit comments