Skip to content

Commit d3310d1

Browse files
author
Test User
committed
feat(session): add session lifecycle management with auto-reset triggers
- Add session management functions: get_session_id(), reset_session(), log_session_transition(), init_session_tracking() - Session auto-reset on: circuit breaker open, manual interrupt, project completion, manual circuit reset - Add --reset-session CLI flag for manual session reset - Add session history tracking (.ralph_session_history, last 50 entries) - New config: RALPH_SESSION_FILE, RALPH_SESSION_HISTORY_FILE - Add 26 comprehensive tests for session continuity (TDD) - All 265 tests pass (up from 239) - Update CLAUDE.md with v0.9.7 release notes
1 parent 3a474b4 commit d3310d1

3 files changed

Lines changed: 536 additions & 4 deletions

File tree

CLAUDE.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
66

77
This is the Ralph for Claude Code repository - an autonomous AI development loop system that enables continuous development cycles with intelligent exit detection and rate limiting.
88

9-
**Version**: v0.9.6 | **Tests**: 239 passing (100% pass rate) | **CI/CD**: GitHub Actions
9+
**Version**: v0.9.7 | **Tests**: 265 passing (100% pass rate) | **CI/CD**: GitHub Actions
1010

1111
## Core Architecture
1212

@@ -37,6 +37,9 @@ The system uses a modular architecture with reusable components in the `lib/` di
3737
- Extracts structured fields: status, exit_signal, work_type, files_modified
3838
- **Session management**: `store_session_id()`, `get_last_session_id()`, `should_resume_session()`
3939
- Automatic session persistence to `.claude_session_id` file with 24-hour expiration
40+
- Session lifecycle: `get_session_id()`, `reset_session()`, `log_session_transition()`, `init_session_tracking()`
41+
- Session history tracked in `.ralph_session_history` (last 50 transitions)
42+
- Session auto-reset on: circuit breaker open, manual interrupt, project completion
4043
- Detects test-only loops and stuck error patterns
4144
- Two-stage error filtering to eliminate false positives
4245
- Multi-line error matching for accurate stuck loop detection
@@ -81,6 +84,9 @@ ralph --status
8184
# Circuit breaker management
8285
ralph --reset-circuit
8386
ralph --circuit-status
87+
88+
# Session management
89+
ralph --reset-session # Reset session state manually
8490
```
8591

8692
### Monitoring
@@ -275,13 +281,14 @@ Ralph uses advanced error detection with two-stage filtering to eliminate false
275281

276282
## Test Suite
277283

278-
### Test Files (239 tests total)
284+
### Test Files (265 tests total)
279285

280286
| File | Tests | Description |
281287
|------|-------|-------------|
282288
| `test_cli_parsing.bats` | 27 | CLI argument parsing for all 12 flags |
283289
| `test_cli_modern.bats` | 29 | Modern CLI commands (Phase 1.1) + build_claude_command fix |
284290
| `test_json_parsing.bats` | 36 | JSON output format parsing + Claude CLI format + session management |
291+
| `test_session_continuity.bats` | 26 | Session lifecycle management + circuit breaker integration |
285292
| `test_exit_detection.bats` | 20 | Exit signal detection |
286293
| `test_rate_limiting.bats` | 15 | Rate limiting behavior |
287294
| `test_loop_execution.bats` | 20 | Integration tests |
@@ -304,6 +311,23 @@ bats tests/unit/test_cli_parsing.bats
304311

305312
## Recent Improvements
306313

314+
### Session Lifecycle Management (v0.9.7)
315+
- Added complete session lifecycle management with automatic reset triggers:
316+
- `get_session_id()` - Retrieves current session from `.ralph_session`
317+
- `reset_session(reason)` - Clears session with reason logging
318+
- `log_session_transition()` - Records transitions to `.ralph_session_history`
319+
- `init_session_tracking()` - Initializes session file with validation
320+
- Session auto-reset integration points:
321+
- Circuit breaker open events (stagnation detection)
322+
- Manual interrupt (Ctrl+C / SIGINT)
323+
- Project completion (graceful exit)
324+
- Manual circuit breaker reset (`--reset-circuit`)
325+
- Added `--reset-session` CLI flag for manual session reset
326+
- Session history tracking (last 50 transitions) for debugging
327+
- New configuration constants: `RALPH_SESSION_FILE`, `RALPH_SESSION_HISTORY_FILE`
328+
- Added 26 new tests for session continuity features
329+
- Test count: 265 (up from 239)
330+
307331
### JSON Output & Session Management (v0.9.6)
308332
- Extended `parse_json_response()` to support Claude Code CLI JSON format
309333
- Supports `result`, `sessionId`, and `metadata` fields alongside existing flat format

ralph_loop.sh

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ CLAUDE_USE_CONTINUE=true # Enable session continuity
3333
CLAUDE_SESSION_FILE=".claude_session_id" # Session ID persistence file
3434
CLAUDE_MIN_VERSION="2.0.76" # Minimum required Claude CLI version
3535

36+
# Session management configuration (Phase 1.2)
37+
RALPH_SESSION_FILE=".ralph_session" # Ralph-specific session tracking
38+
RALPH_SESSION_HISTORY_FILE=".ralph_session_history" # Session transition history
39+
SESSION_EXPIRATION_SECONDS=86400 # 24 hours in seconds
40+
3641
# Valid tool patterns for --allowed-tools validation
3742
# Tools can be exact matches or pattern matches with wildcards in parentheses
3843
VALID_TOOL_PATTERNS=(
@@ -477,6 +482,125 @@ save_claude_session() {
477482
fi
478483
}
479484

485+
# =============================================================================
486+
# SESSION LIFECYCLE MANAGEMENT FUNCTIONS (Phase 1.2)
487+
# =============================================================================
488+
489+
# Get current session ID from Ralph session file
490+
# Returns: session ID string or empty if not found
491+
get_session_id() {
492+
if [[ ! -f "$RALPH_SESSION_FILE" ]]; then
493+
echo ""
494+
return 0
495+
fi
496+
497+
# Extract session_id from JSON file
498+
local session_id=$(jq -r '.session_id // ""' "$RALPH_SESSION_FILE" 2>/dev/null)
499+
if [[ "$session_id" == "null" ]]; then
500+
session_id=""
501+
fi
502+
echo "$session_id"
503+
return 0
504+
}
505+
506+
# Reset session with reason logging
507+
# Usage: reset_session "reason_for_reset"
508+
reset_session() {
509+
local reason=${1:-"manual_reset"}
510+
511+
# Log the transition before clearing
512+
local old_session_id=$(get_session_id)
513+
514+
# Clear the session file
515+
if [[ -f "$RALPH_SESSION_FILE" ]]; then
516+
cat > "$RALPH_SESSION_FILE" << EOF
517+
{
518+
"session_id": "",
519+
"created_at": "",
520+
"last_used": "",
521+
"reset_at": "$(get_iso_timestamp)",
522+
"reset_reason": "$reason"
523+
}
524+
EOF
525+
fi
526+
527+
# Also clear the Claude session file for consistency
528+
if [[ -f "$CLAUDE_SESSION_FILE" ]]; then
529+
rm -f "$CLAUDE_SESSION_FILE"
530+
fi
531+
532+
# Log the session transition
533+
log_session_transition "active" "reset" "$reason" "${loop_count:-0}"
534+
535+
log_status "INFO" "Session reset: $reason"
536+
}
537+
538+
# Log session state transitions to history file
539+
# Usage: log_session_transition from_state to_state reason loop_number
540+
log_session_transition() {
541+
local from_state=$1
542+
local to_state=$2
543+
local reason=$3
544+
local loop_number=${4:-0}
545+
546+
# Initialize history file if needed
547+
if [[ ! -f "$RALPH_SESSION_HISTORY_FILE" ]]; then
548+
echo '[]' > "$RALPH_SESSION_HISTORY_FILE"
549+
fi
550+
551+
# Create transition entry
552+
local transition
553+
transition=$(jq -n \
554+
--arg timestamp "$(get_iso_timestamp)" \
555+
--arg from_state "$from_state" \
556+
--arg to_state "$to_state" \
557+
--arg reason "$reason" \
558+
--argjson loop_number "$loop_number" \
559+
'{
560+
timestamp: $timestamp,
561+
from_state: $from_state,
562+
to_state: $to_state,
563+
reason: $reason,
564+
loop_number: $loop_number
565+
}')
566+
567+
# Append to history and keep only last 50 entries
568+
local history=$(cat "$RALPH_SESSION_HISTORY_FILE" 2>/dev/null || echo '[]')
569+
history=$(echo "$history" | jq ". += [$transition] | .[-50:]")
570+
echo "$history" > "$RALPH_SESSION_HISTORY_FILE"
571+
}
572+
573+
# Initialize session tracking (called at loop start)
574+
init_session_tracking() {
575+
# Create session file if it doesn't exist
576+
if [[ ! -f "$RALPH_SESSION_FILE" ]]; then
577+
cat > "$RALPH_SESSION_FILE" << EOF
578+
{
579+
"session_id": "",
580+
"created_at": "$(get_iso_timestamp)",
581+
"last_used": "",
582+
"reset_at": "",
583+
"reset_reason": ""
584+
}
585+
EOF
586+
log_status "INFO" "Initialized session tracking"
587+
fi
588+
589+
# Validate existing session file
590+
if ! jq empty "$RALPH_SESSION_FILE" 2>/dev/null; then
591+
log_status "WARN" "Corrupted session file detected, recreating..."
592+
cat > "$RALPH_SESSION_FILE" << EOF
593+
{
594+
"session_id": "",
595+
"created_at": "$(get_iso_timestamp)",
596+
"last_used": "",
597+
"reset_at": "",
598+
"reset_reason": "corrupted_file_recovery"
599+
}
600+
EOF
601+
fi
602+
}
603+
480604
# Global array for Claude command arguments (avoids shell injection)
481605
declare -a CLAUDE_CMD_ARGS=()
482606

@@ -731,6 +855,7 @@ EOF
731855
# Cleanup function
732856
cleanup() {
733857
log_status "INFO" "Ralph loop interrupted. Cleaning up..."
858+
reset_session "manual_interrupt"
734859
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE" 2>/dev/null || echo "0")" "interrupted" "stopped"
735860
exit 0
736861
}
@@ -785,6 +910,7 @@ main() {
785910

786911
# Check circuit breaker before attempting execution
787912
if should_halt_execution; then
913+
reset_session "circuit_breaker_open"
788914
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "circuit_breaker_open" "halted" "stagnation_detected"
789915
log_status "ERROR" "🛑 Circuit breaker has opened - execution halted"
790916
break
@@ -800,13 +926,14 @@ main() {
800926
local exit_reason=$(should_exit_gracefully)
801927
if [[ "$exit_reason" != "" ]]; then
802928
log_status "SUCCESS" "🏁 Graceful exit triggered: $exit_reason"
929+
reset_session "project_complete"
803930
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "graceful_exit" "completed" "$exit_reason"
804-
931+
805932
log_status "SUCCESS" "🎉 Ralph has completed the project! Final stats:"
806933
log_status "INFO" " - Total loops: $loop_count"
807934
log_status "INFO" " - API calls used: $(cat "$CALL_COUNT_FILE")"
808935
log_status "INFO" " - Exit reason: $exit_reason"
809-
936+
810937
break
811938
fi
812939

@@ -825,6 +952,7 @@ main() {
825952
sleep 5
826953
elif [ $exec_result -eq 3 ]; then
827954
# Circuit breaker opened
955+
reset_session "circuit_breaker_trip"
828956
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "circuit_breaker_open" "halted" "stagnation_detected"
829957
log_status "ERROR" "🛑 Circuit breaker has opened - halting loop"
830958
log_status "INFO" "Run 'ralph --reset-circuit' to reset the circuit breaker after addressing issues"
@@ -896,6 +1024,7 @@ Options:
8961024
-t, --timeout MIN Set Claude Code execution timeout in minutes (default: $CLAUDE_TIMEOUT_MINUTES)
8971025
--reset-circuit Reset circuit breaker to CLOSED state
8981026
--circuit-status Show circuit breaker status and exit
1027+
--reset-session Reset session state and exit (clears session continuity)
8991028
9001029
Modern CLI Options (Phase 1.1):
9011030
--output-format FORMAT Set Claude output format: json or text (default: $CLAUDE_OUTPUT_FORMAT)
@@ -968,7 +1097,17 @@ while [[ $# -gt 0 ]]; do
9681097
# Source the circuit breaker library
9691098
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
9701099
source "$SCRIPT_DIR/lib/circuit_breaker.sh"
1100+
source "$SCRIPT_DIR/lib/date_utils.sh"
9711101
reset_circuit_breaker "Manual reset via command line"
1102+
reset_session "manual_circuit_reset"
1103+
exit 0
1104+
;;
1105+
--reset-session)
1106+
# Reset session state only
1107+
SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
1108+
source "$SCRIPT_DIR/lib/date_utils.sh"
1109+
reset_session "manual_reset_flag"
1110+
echo -e "${GREEN}✅ Session state reset successfully${NC}"
9721111
exit 0
9731112
;;
9741113
--circuit-status)

0 commit comments

Comments
 (0)