Description
Ralph exits prematurely after 2 loops based on confidence-scoring heuristics, even when Claude explicitly reports EXIT_SIGNAL: false in the RALPH_STATUS block. This prevents projects requiring multiple iterations from running to completion.
Environment
- Ralph Version: v0.9.8
- OS: macOS / Linux
- Shell: Bash
Steps to Reproduce
- Create a project with iterative stop conditions (e.g., quality score >= 95%)
- Run Ralph:
ralph --timeout 30 --allowed-tools "Write,Edit,Read,Bash(*)" --verbose
- Observe Claude doing productive work and reporting:
---RALPH_STATUS---
STATUS: IN_PROGRESS
EXIT_SIGNAL: false
RECOMMENDATION: Continue processing...
---END_RALPH_STATUS---
- Ralph exits after 2 loops with:
Exit condition: Strong completion indicators (2)
Expected Behavior
Ralph should respect Claude's explicit EXIT_SIGNAL: false and continue iterating until Claude reports EXIT_SIGNAL: true (indicating project requirements are met).
Actual Behavior
Ralph exits after 2 loops regardless of Claude's EXIT_SIGNAL value. The .response_analysis file shows:
{
"analysis": {
"exit_signal": false,
"has_completion_signal": false,
"confidence_score": 70
}
}
Despite exit_signal: false, Ralph triggers exit because confidence_score >= 60 adds the loop to completion_indicators, and 2+ indicators triggers exit.
Root Cause
In ralph_loop.sh, the should_exit_gracefully() function (~line 313) checks:
if [[ $recent_completion_indicators -ge 2 ]]; then
log_status "WARN" "Exit condition: Strong completion indicators ($recent_completion_indicators)"
echo "project_complete"
return 0
fi
This check does not consult Claude's explicit exit_signal from .response_analysis. The confidence scoring triggers on natural language patterns like "Complete", "Perfect", "successfully" - even during productive IN_PROGRESS iterations.
Proposed Fix
Modify the completion indicators check to respect Claude's explicit EXIT_SIGNAL:
# 3. Strong completion indicators (only if Claude's EXIT_SIGNAL is true)
local claude_exit_signal="false"
if [[ -f ".response_analysis" ]]; then
claude_exit_signal=$(jq -r '.analysis.exit_signal // false' ".response_analysis" 2>/dev/null || echo "false")
fi
if [[ $recent_completion_indicators -ge 2 ]] && [[ "$claude_exit_signal" == "true" ]]; then
log_status "WARN" "Exit condition: Strong completion indicators ($recent_completion_indicators) with EXIT_SIGNAL=true" >&2
echo "project_complete"
return 0
elif [[ $recent_completion_indicators -ge 2 ]]; then
log_status "INFO" "DEBUG: Completion indicators ($recent_completion_indicators) but EXIT_SIGNAL=false, continuing..." >&2
fi
Important: The >&2 is critical - without it, log_status output goes to stdout and gets captured as the function's return value (non-empty = exit reason), causing unintended exits.
Behavior After Fix
| Scenario |
completion_indicators |
EXIT_SIGNAL |
Result |
| Work in progress |
>= 2 |
false |
Continue (fixed) |
| Project complete |
>= 2 |
true |
Exit |
| Early iterations |
< 2 |
false |
Continue |
Verified Fix
I've tested this fix on a documentation refinement project:
- Before fix: Exited after 2-3 loops at 65% quality
- After fix: Ran 17+ loops, reached 94% quality and continuing
Related Files
ralph_loop.sh - should_exit_gracefully() function
lib/response_analyzer.sh - Parses RALPH_STATUS and populates .response_analysis
.response_analysis - Contains exit_signal from Claude
.exit_signals - Tracks completion_indicators array
Description
Ralph exits prematurely after 2 loops based on confidence-scoring heuristics, even when Claude explicitly reports
EXIT_SIGNAL: falsein the RALPH_STATUS block. This prevents projects requiring multiple iterations from running to completion.Environment
Steps to Reproduce
ralph --timeout 30 --allowed-tools "Write,Edit,Read,Bash(*)" --verboseExit condition: Strong completion indicators (2)Expected Behavior
Ralph should respect Claude's explicit
EXIT_SIGNAL: falseand continue iterating until Claude reportsEXIT_SIGNAL: true(indicating project requirements are met).Actual Behavior
Ralph exits after 2 loops regardless of Claude's EXIT_SIGNAL value. The
.response_analysisfile shows:{ "analysis": { "exit_signal": false, "has_completion_signal": false, "confidence_score": 70 } }Despite
exit_signal: false, Ralph triggers exit becauseconfidence_score >= 60adds the loop tocompletion_indicators, and 2+ indicators triggers exit.Root Cause
In
ralph_loop.sh, theshould_exit_gracefully()function (~line 313) checks:This check does not consult Claude's explicit
exit_signalfrom.response_analysis. The confidence scoring triggers on natural language patterns like "Complete", "Perfect", "successfully" - even during productive IN_PROGRESS iterations.Proposed Fix
Modify the completion indicators check to respect Claude's explicit EXIT_SIGNAL:
Important: The
>&2is critical - without it,log_statusoutput goes to stdout and gets captured as the function's return value (non-empty = exit reason), causing unintended exits.Behavior After Fix
Verified Fix
I've tested this fix on a documentation refinement project:
Related Files
ralph_loop.sh-should_exit_gracefully()functionlib/response_analyzer.sh- Parses RALPH_STATUS and populates.response_analysis.response_analysis- Containsexit_signalfrom Claude.exit_signals- Trackscompletion_indicatorsarray