[BUG] ralph-loop Stop hook silently fails on Windows after Claude Code 2.1.126 (worked on 2.1.119)

Resolved 💬 2 comments Opened May 4, 2026 by sevidosan Closed Jun 2, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

The ralph-loop plugin Stop hook fires correctly on Claude Code 2.1.119 but silently fails to fire on Claude Code 2.1.126 (Windows + Git Bash).
The hook script itself is valid — when invoked manually it returns the correct decision: block JSON. But Claude Code 2.1.126 doesn't appear to invoke it
at end-of-turn anymore.

This effectively kills the plugin on the latest Windows builds — the loop runs exactly 1 iteration and goes idle waiting for a hook that never fires.

### Evidence — same machine, same plugin, only Claude Code version differs

Counted hook execution events (type:"attachment" + attachment.type:"hook_system_message" + hookEvent:"Stop") across JSONL transcripts:

| Session | CC version | Hook events | Outcome |
|---|---|---|---|
| atlas, 2026-04-30 | 2.1.119 | 175 | Loop ran for hours, completed normally |
| atlas, 2026-05-02 | 2.1.119 | 51 | Loop ran 17 iters, completed |
| atlas, 2026-04-30 (other) | 2.1.119 | 7 | Worked |
| guberman3, 2026-05-04 | 2.1.126 | 0 | Stopped after iter 1 |
| guberman3, 2026-05-04 (other) | 2.1.126 | 0 | Stopped after iter 1 |

The session that broke shows the agent ending iter 1 normally, then nothing:

  • 15:52:19.316 UTC — assistant text "Iter 1 done — commit f7066f9"
  • 15:52:19.393 UTC — system/turn_duration event (turn ended)
  • 15:55:22.817 UTC — system/away_summary event (3 min later, session went idle)
  • No hook_system_message event between turn end and away
  • No decision:"block" reinjection
  • 18 minutes of idle until the user typed "continue manually"

### Manual hook invocation works fine

Running stop-hook.sh directly with simulated stdin input returns the correct JSON:

``json
{
"decision": "block",
"reason": "<original prompt>",
"systemMessage": "🔄 Ralph iteration 2 | To stop: output <promise>DONE</promise>..."
}
``

The iteration: field in .claude/ralph-loop.local.md increments correctly. So the script is healthy — Claude Code 2.1.126 just isn't dispatching the
Stop event to it on Windows builds.

### What I ruled out

  • Not the known bugs from issue #394 — no cd in agent commands; state file not deleted; relative path resolves correctly because cwd stayed at project

root throughout the run

  • Not a missing utility — bash, jq, perl, sed, awk, grep, cat all present in Git Bash 2.49
  • Not away_summary itself — sessions on 2.1.119 also produced away_summary events alongside hook events (10 away_summary in one atlas session,

coexisting with 175 hook events)

  • Not lifecycle/permissions/settings — same ~/.claude/settings.json for both working (atlas, 2.1.119) and broken (guberman3, 2.1.126) sessions

### About me

I'm a software engineer building agent systems on Claude Code. Happy to provide more JSONL artifacts, transcripts, or repro environment if useful for
triage.

What Should Happen?

After the agent ends a turn while a ralph-loop.local.md state file is active in the project root:

  1. Claude Code dispatches the Stop event to registered plugin hooks
  2. The plugin's stop-hook.sh script executes with the standard stdin payload (session_id, transcript_path)
  3. The script reads the state file, validates iteration < max_iterations, checks the last assistant message for <promise>COMPLETION_PROMISE</promise>,

and either:

  • Allows exit if max_iterations reached or completion promise emitted, OR
  • Returns {"decision": "block", "reason": "<original prompt>", "systemMessage": "🔄 Ralph iteration N..."} to re-feed the original prompt and

increment the iteration counter

  1. Claude Code re-injects the reason field as a new user message, surfaces the systemMessage to the user, and the agent proceeds with iter N+1

This is the documented behavior of the plugin and matches what was observed on Claude Code 2.1.119, where a single overnight session produced 175
hook events
(one per Stop), allowing the loop to run continuously for hours.

On Claude Code 2.1.126, none of the above happens — hook_system_message events are entirely absent from the JSONL transcript, even though the state
file is present, the script is executable, and manual invocation produces the correct output.

### Suggestions

  1. If /loop dynamic mode + ScheduleWakeup is the intended successor (it's a great design — works without bash, context accumulates,

Anthropic-maintained), consider deprecating ralph-loop officially in the plugin README with a migration note pointing at /loop. The plugin still
installs and runs setup successfully, which misleads users into thinking the issue is their setup.

  1. If ralph-loop is meant to keep working, investigate why the Stop event isn't dispatched to plugin hooks on Claude Code 2.1.126 Windows builds.

Possible angles: change in event lifecycle around away_summary, change in plugin hook registration timing, change in how Stop fires when
bypassPermissions mode is active.

  1. Either way, surface a clear log/error when a hook is registered but not invoked — silent failure is the worst-case UX. A debug log entry like `[hook]

Stop event fired, dispatching to plugin X` would have made this trivially diagnosable.

Error Messages/Logs

Steps to Reproduce

Environment

  • OS: Windows 11 Home Single Language 10.0.26200
  • Shell: PowerShell + Git Bash 2.49
  • Claude Code (broken): 2.1.126 (native Windows installer, single binary at ~/.local/bin/claude.exe)
  • Claude Code (works): 2.1.119 (same machine, same plugin, prior version)
  • Plugin: ralph-loop@1.0.0 from claude-plugins-official
  • Plan: Max
  • ~/.claude/settings.json excerpt:

``json
{
"model": "opus[1m]",
"permissions": { "defaultMode": "bypassPermissions" },
"alwaysThinkingEnabled": true,
"skipDangerousModePermissionPrompt": true
}
``

### Reproduction steps

  1. Install Claude Code 2.1.126 for Windows (native installer)
  2. Install Git for Windows (provides Git Bash with bash/jq/perl/sed/awk/grep)
  3. Install the plugin:

``
claude plugin install ralph-loop@claude-plugins-official
``

  1. Confirm install:

``
claude plugin list
`
Expect:
ralph-loop@claude-plugins-official Version: 1.0.0 Status: ✔ enabled`

  1. Create a test git project:

``bash
mkdir test-ralph && cd test-ralph
git init
echo "iter 0" > log.md
git add log.md && git commit -m "init"
``

  1. Start Claude Code in that directory and run:

``
/ralph-loop:ralph-loop "Append 'iter N done' to log.md, commit, then end your turn." --max-iterations 5 --completion-promise "ALL_DONE"
``

  1. Observed: agent appends iter 1, commits, ends turn. Session goes idle. After ~3 min, system/away_summary appears in the JSONL transcript. **No

further iterations occur.** Loop is dead.

  1. Verify the hook script itself works (proves the script is healthy, the issue is dispatch):

``bash
# In Git Bash, from the project root:
echo '{"session_id":"<paste from JSONL>","transcript_path":"<paste path to current session JSONL>"}' \
| bash "$HOME/.claude/plugins/marketplaces/claude-plugins-official/plugins/ralph-loop/hooks/stop-hook.sh"
`
Expected: returns valid JSON with
"decision":"block" and the prompt re-fed in reason`.
Actual: returns valid JSON correctly. So the script works — Claude Code just isn't calling it.

  1. Compare to working version (if you have access to 2.1.119):
  • Same project, same plugin, same .claude/ralph-loop.local.md
  • Run the same /ralph-loop:ralph-loop command
  • Hook fires after each turn; hook_system_message events appear in JSONL; loop iterates correctly

### Files to inspect

  • ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl — transcript. Search for hook_system_message (zero matches on 2.1.126 broken sessions; many on

2.1.119 working sessions).

  • ~/.claude/plugins/marketplaces/claude-plugins-official/plugins/ralph-loop/hooks/stop-hook.sh — the script that should be invoked but isn't.
  • <project>/.claude/ralph-loop.local.md — state file. Verify iteration: stays at 1 (not incremented) and session_id: may be empty if

CLAUDE_CODE_SESSION_ID env var isn't set during setup.

Claude Model

Opus

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.119

Claude Code Version

2.1.126

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

_No response_

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗