claude-code - 💡(How to fix) Fix [BUG] ralph-loop Stop hook silently fails on Windows after Claude Code 2.1.126 (worked on 2.1.119) [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#56096Fetched 2026-05-05 05:58:20
View on GitHub
Comments
1
Participants
2
Timeline
7
Reactions
1
Author
Timeline (top)
labeled ×6commented ×1

Error Message

  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]

Error Messages/Logs

Root Cause

  • 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

Fix Action

Fix / Workaround

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.

  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
  4. 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

  5. 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.

Code Example

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

---



---

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

---

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

---

claude plugin list

---

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

---

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

---

# 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"
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • 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:

SessionCC versionHook eventsOutcome
atlas, 2026-04-302.1.119175Loop ran for hours, completed normally
atlas, 2026-05-022.1.11951Loop ran 17 iters, completed
atlas, 2026-04-30 (other)2.1.1197Worked
guberman3, 2026-05-042.1.1260Stopped after iter 1
guberman3, 2026-05-04 (other)2.1.1260Stopped 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:

{
  "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
  4. 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.

  2. 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.

  3. 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: [email protected] from claude-plugins-official
  • Plan: Max
  • ~/.claude/settings.json excerpt:
    {
      "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
  4. Confirm install:

    claude plugin list

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

  5. Create a test git project:

    mkdir test-ralph && cd test-ralph
    git init
    echo "iter 0" > log.md
    git add log.md && git commit -m "init"
  6. 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"
  7. 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.

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

    # 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.

  9. 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

extent analysis

TL;DR

The ralph-loop plugin's Stop hook fails to fire on Claude Code 2.1.126, causing the loop to run only one iteration, and a potential fix could involve investigating the event lifecycle or plugin hook registration timing.

Guidance

  • Investigate the difference in event lifecycle or plugin hook registration timing between Claude Code 2.1.119 and 2.1.126 to identify why the Stop event isn't dispatched to plugin hooks on Windows builds.
  • Verify that the stop-hook.sh script is correctly registered and executable in the Claude Code 2.1.126 environment.
  • Check the Claude Code documentation for any changes in plugin hook invocation or event handling between versions 2.1.119 and 2.1.126.
  • Consider adding debug logging to the ralph-loop plugin to surface any errors or issues during hook invocation.

Example

No code example is provided as the issue seems to be related to the interaction between the ralph-loop plugin and Claude Code, and without more information about the internal workings of Claude Code, it's difficult to provide a specific code solution.

Notes

The issue seems to be specific to the Windows build of Claude Code 2.1.126, and the ralph-loop plugin works correctly on version 2.1.119. The problem may be related to changes in the event lifecycle or plugin hook registration timing between these two versions.

Recommendation

Apply a workaround by using the /loop dynamic mode with ScheduleWakeup as an alternative to the ralph-loop plugin, as suggested in the issue, until the root cause of the issue is identified and fixed.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] ralph-loop Stop hook silently fails on Windows after Claude Code 2.1.126 (worked on 2.1.119) [1 comments, 2 participants]