fix: install Stop hook once at loop startup, not per-iteration

Per-iteration install/remove had a race condition: settings.local.json
was written immediately before CC started, and CC could read the old
file (without the hook) on the first iteration.

Now the hook is installed once when loop.sh starts and removed on exit.
The AGENT_LOOP_ACTIVE env var guard ensures it only fires for CC sessions
spawned by the loop, so keeping it installed the whole time is safe.
This commit is contained in:
2026-04-02 10:51:48 -04:00
parent a1a3dfbd63
commit b516492a91
3 changed files with 7 additions and 9 deletions

12
loop.sh
View File

@@ -158,8 +158,11 @@ finish() {
read -r -t 30 2>/dev/null || true
exit "$exit_code"
}
# NOTE: Stop hook is installed/removed per-agent in run_agent(), not globally.
# This prevents the hook from killing the orchestrating CC session.
# Install Stop hook once at startup. The AGENT_LOOP_ACTIVE env var guard ensures
# it only fires for CC sessions spawned by this loop (not the user's other sessions).
# Installing once avoids a race condition where per-iteration install_hooks writes
# settings.local.json just before CC starts, and CC reads the old file.
[ "$AUTO_HOOKS" = true ] && install_hooks
trap cleanup EXIT INT TERM
check_archive
@@ -204,9 +207,6 @@ run_agent() {
rm -f "$LOOP_DIR/.verdict"
local agent_exit=0
# Install Stop hook just before claude starts, remove after it exits.
# This scopes the hook to only affect the loop's claude sessions.
[ "$AUTO_HOOKS" = true ] && install_hooks
(
case "$TOOL" in
@@ -222,8 +222,6 @@ run_agent() {
;;
esac
) || agent_exit=$?
[ "$AUTO_HOOKS" = true ] && remove_hooks
sleep 2 # Brief pause between sessions
# Read verdict from file if evaluator wrote one