Root cause: Stale completion indicators in .exit_signals and .response_analysis
files persisted across sessions, causing premature exit when combined with
normal completion indicator increments.
Changes:
- Enhanced reset_session() to clear .exit_signals file (resets to empty structure)
- Enhanced reset_session() to remove .response_analysis file
- Session reset now comprehensively clears all exit-related state
Added 2 new tests:
- reset_session clears exit_signals file to prevent premature exit
- reset_session prevents issue #91 scenario (stale completion indicators)
Test count: 321 (up from 319)
Fixes#91
Merged origin/main into PR branch and applied review feedback:
Review fixes:
- Guard against empty result_obj if jq fails (Macroscope)
- Prioritize result object's session_id over init message (CodeRabbit)
- Add regression test for arrays with session_id only in result element
Resolved conflicts:
- CLAUDE.md: Updated test count to 319
All 319 tests pass.
Claude Code CLI outputs a JSON array instead of a single object:
[{type: "system", ...}, {type: "assistant", ...}, {type: "result", ...}]
This caused parse_json_response to fail with "jq: invalid JSON text"
because it assumed the top-level JSON was an object.
Changes:
- Detect if JSON is an array before parsing
- Extract the "result" type message from the array
- Preserve session_id from init message for continuity
- Normalize to object format for existing parsing logic
- Clean up temporary file after processing
Fixes#112
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(structure): migrate Ralph files to .ralph/ subfolder
BREAKING CHANGE: Ralph configuration files now live in .ralph/ subfolder
This refactoring moves all Ralph-specific files into a hidden .ralph/
directory while keeping src/ at the project root. This improves
compatibility with existing tooling and keeps the project root clean.
Changes:
- Move PROMPT.md, @fix_plan.md, @AGENT.md to .ralph/
- Move specs/, logs/, docs/generated/, examples/ to .ralph/
- Move state files (.response_analysis, .circuit_breaker_state, etc.) to .ralph/
- Keep src/ at project root (unchanged)
- Add RALPH_DIR=".ralph" configuration variable
- Add ralph-migrate command for existing projects
- Create migrate_to_ralph_folder.sh migration script
- Update all path references in scripts and tests
- Update documentation (README.md, CLAUDE.md)
New project structure:
project/
├── .ralph/ # Ralph configuration
│ ├── PROMPT.md
│ ├── @fix_plan.md
│ ├── @AGENT.md
│ ├── specs/
│ ├── logs/
│ └── docs/generated/
└── src/ # Source code (unchanged)
Migration: Run `ralph-migrate` in existing projects to upgrade.
All 310 tests pass (100% pass rate).
* chore: add .claude/settings.local.json to .gitignore
* fix: address code review feedback for .ralph/ subfolder structure
Fixes multiple path-related issues identified in code review:
Test fixes:
- Fix create_sample_prompt to use $RALPH_DIR/PROMPT.md in test_session_continuity.bats
- Fix result_file path to use $RALPH_DIR/.json_parse_result in test_json_parsing.bats
- Fix @fix_plan.md and .response_analysis paths in test_cli_modern.bats
- Update templates directory missing test to account for global fallback
Template fix:
- Fix @fix_plan.md reference in templates/PROMPT.md to use .ralph/ prefix
Script fixes:
- Fix PROMPT_FILE comparison in ralph_loop.sh to use $RALPH_DIR/PROMPT.md
- Fix examples migration logic in migrate_to_ralph_folder.sh (remove premature mkdir)
- Move templates directory check AFTER cd in setup.sh (was checking wrong location)
- Add template directory validation with fallback to global templates
All 310 tests pass.
* Update migrate_to_ralph_folder.sh
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
* fix: address code review feedback for .ralph/ subfolder structure
Code Review Fixes:
- Fix test_json_parsing.bats: all result_file and session file paths now use $RALPH_DIR prefix
- Fix ralph_loop.sh help text: paths now show .ralph/.ralph_session, .ralph/.call_count, etc.
- Fix migrate_to_ralph_folder.sh:
- Proper error handling for date command (separate local declaration)
- Use cp -a source/. dest/ pattern to preserve dotfiles and attributes
- Remove 2>/dev/null suppression to surface copy errors
- Update create_files.sh to use .ralph/ structure for embedded scripts
- Update .gitignore with all .ralph/ state file paths
- Add old structure detection in ralph_loop.sh with helpful migration message
Version Update:
- Bump to v0.10.0 (breaking change: structural reorganization)
- Update README.md and CLAUDE.md with new version and release notes
- Add ralph-migrate documentation to Key Commands section
All 310 tests pass.
---------
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
* feat(timeout): add cross-platform timeout support for macOS
Add portable timeout wrapper that automatically detects and uses the
appropriate timeout command based on the platform:
- Linux: Uses standard GNU `timeout` from coreutils
- macOS: Uses `gtimeout` from Homebrew coreutils
Changes:
- Add lib/timeout_utils.sh with detect_timeout_command() and
portable_timeout() functions
- Update ralph_loop.sh to source timeout_utils.sh and use
portable_timeout for Claude Code execution
- Update install.sh to check for coreutils on macOS and provide
installation instructions
- Update test mocks to include gtimeout and portable_timeout
- Update README.md with macOS coreutils installation instructions
- Update CLAUDE.md with timeout_utils.sh documentation
Users on macOS now need to install coreutils: brew install coreutils
* Update model reference in opencode-review workflow
* Update model name in opencode-review workflow
* Update model version in opencode-review workflow
* Update model version in opencode-review workflow
* Update lib/timeout_utils.sh
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
* Update opencode-review.yml
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
Major updates:
- Version bumped to v0.9.9
- Test count updated to 308 (from 276)
- Added v0.9.9 release notes: EXIT_SIGNAL gate fix, uninstall script, session expiration
- New "Uninstalling Ralph" section with dedicated uninstall.sh
- Updated "Intelligent Exit Detection" with dual-condition check explanation
- Added EXIT_SIGNAL decision table to Configuration section
- New troubleshooting entries: "Premature Exit" and "Session Expired"
- Updated test coverage breakdown (164 unit + 144 integration)
- Added "Clean Uninstall" to Features list
- Updated Command Reference with ./uninstall.sh
* feat: add dedicated uninstall.sh script
Add a standalone uninstall script that provides:
- Safety confirmation prompt before removal (skip with -y/--yes)
- Installation check to verify Ralph is installed
- Removal plan display showing exactly what will be removed
- Consistent styling matching install.sh (colors, logging)
- Help option (-h/--help) for usage information
- Preserves project directories created with ralph-setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add function documentation to uninstall.sh
Address CodeRabbit review comments:
- Add documentation comments to all functions (log, check_installation,
show_removal_plan, confirm_uninstall, remove_commands, remove_ralph_home, main)
- Improve check_installation to detect partial installations by checking
all Ralph commands, not just the main ralph command
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: use safe arithmetic to avoid set -e failure
Replace ((removed++)) with removed=$((removed + 1)) to prevent
script termination when removed is 0, as post-increment returns
exit code 1 when the expression value is 0 under set -e.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Reapply "feat(session): implement session expiration with configurable timeout (#83)"
This reverts commit 1ba55a4b9c.
* fix(session): address code review feedback
- Fix integer overflow: return -1 from get_session_file_age_hours on stat
failure instead of 0, preventing false expiration
- Handle stat failure in init_claude_session with WARN log
- Add comprehensive documentation for return values and expiration strategy
- Add 6 behavioral integration tests that verify actual functionality
- Add inline comments explaining 24-hour default rationale
Test count: 286 → 292 (100% pass rate)
* fix(test): use grep-based verification to fix CI failures
Tests that sourced ralph_loop.sh with --help flag failed in GitHub
Actions due to BATS environment differences. Changed behavioral tests
to grep-based code verification that checks implementation patterns
exist without executing the script.
* fix(test): guard main with BASH_SOURCE for safe sourcing
- Add BASH_SOURCE check to only execute main when script is run directly
- Update tests to source script without --help flag
- Convert grep-based verification tests back to functional tests
- Fixes CI failures caused by script execution during sourcing
---------
Co-authored-by: Test User <test@example.com>
- Add CLAUDE_SESSION_EXPIRY_HOURS configuration variable (default: 24)
- Add get_session_file_age_hours() helper with cross-platform stat support
- Modify init_claude_session() to check session age and remove expired sessions
- Add --session-expiry CLI flag to configure expiration (positive integers only)
- Update help text with new option and example
- Add 10 new tests for session expiration (TDD approach)
Closes#51
Test count: 276 → 286 (100% pass rate)
Co-authored-by: Test User <test@example.com>
- Add GitHub Actions CI badge (dynamic, links to workflow)
- Add MIT License badge (links to LICENSE file)
- Add GitHub Issues badge (dynamic count)
- Keep Awesome Claude Code and X follow badges
- Remove redundant status badge, keep version and tests
- Create CONTRIBUTING.md with 8 sections covering the full contributor
journey: Getting Started, Development Workflow, Code Style, Testing,
PR Process, Code Review, Quality Standards, and Community Guidelines
- Include workflow diagram, quality gates table, and test commands reference
- Update README.md to reference CONTRIBUTING.md, consolidating duplicate
contributor information into the dedicated guide
Add TESTING.md with complete documentation for the Ralph test suite:
- Quick start commands for running tests
- Test organization and directory structure
- BATS syntax guide with examples from the codebase
- Test helper API documentation (assertions, mocks, fixtures)
- Coverage requirements and kcov limitations
- CI/CD integration with GitHub Actions pipeline
- Troubleshooting guide for common issues
- Appendices with quick reference and patterns
Covers all 276 tests across 11 test files.
Reverted changes to issues not created by frankbria:
- #44, #54, #64, #65 removed from phase assignments
- Restored original issue titles on GitHub
- Removed phase labels from community issues
- Updated open issue counts (40 → 36)
- Update test counts (75 -> 276) and all test file details
- Convert from Week-based to Phase-based structure (Phases 1-6)
- Add all GitHub issues organized by phase and priority
- Update version history with v0.9.0-v0.9.8 changes
- Add summary statistics and open issues by priority
- Collapse closed issues into expandable section
- Add version history entries for v0.9.3 through v0.9.8
- Add Session Continuity feature to features list
- Add new Session Continuity configuration section
- Add --reset-session flag to command reference
- Add new test file references (session, import, setup, installation)
- Add detailed docblocks for detect_response_format, parse_conversion_response,
and check_claude_version functions
- Declare global PARSED_* variables near top of script with documentation
- Fix bug where convert_prd was called with subdirectory path after cd
(now uses basename since file is copied to project root)
All 276 tests pass.
- Convert CLAUDE_ALLOWED_TOOLS to bash array for proper quoting
- Use array expansion "${CLAUDE_ALLOWED_TOOLS[@]}" in CLI invocation
- Default empty version components to 0 (handles "2.1" style versions)
- Add stderr_file cleanup in JSON error path
- Add type validation for PARSED_FILES_CREATED before array iteration
- Check for empty file names in JSON array iteration
- Fix stale test counts in README.md (165 → 276, 8 → 11 test files)
- Fix check_claude_version() to use numeric semantic version comparison
- Fix detect_response_format() to read first non-whitespace character
- Wire PARSED_RESULT into success message output
- Wire PARSED_FILES_CREATED into file verification logic
- Add --allowedTools flag to CLI invocation using CLAUDE_ALLOWED_TOOLS
- Separate stderr to avoid corrupting JSON output file
- Clean up stderr file on completion and error
- Update README.md version badges to v0.9.8 and 276 tests
- Update roadmap section with current test coverage breakdown
- Add --output-format json flag for structured Claude CLI responses
- Implement detect_response_format() for JSON vs text detection
- Implement parse_conversion_response() for extracting JSON fields
- Add check_claude_version() for modern CLI feature detection
- Enhance error handling with structured JSON error messages
- Improve file verification with JSON-derived status information
- Maintain backward compatibility with automatic text fallback
- Add 11 new TDD tests for modern CLI features (tests 23-33)
- Update README.md with Modern CLI Features section
- Update CLAUDE.md with v0.9.8 release notes
Test count: 276 (up from 265)
- Fix SC2155: separate declare from assign in get_session_id(),
log_session_transition(), init_session_tracking()
- Use jq for safe JSON generation in reset_session() and init_session_tracking()
instead of heredocs (prevents special character issues)
- Add corruption tolerance to log_session_transition() with JSON validation
and fallback to empty array on parse failures
- Add generate_session_id() to create unique session IDs (ralph-<epoch>-<random>)
- Add update_session_last_used() helper called on each loop iteration
- init_session_tracking() now generates unique session_id and sets last_used
- Add session files to .gitignore (.ralph_session, .ralph_session_history,
.claude_session_id)
All 265 tests pass.
- Add init_session_tracking() call in main() before loop starts
- Use literal escape codes for color in --reset-session output
- Remove conditional in reset_session() to always create file
- Remove unused old_session_id variable
- Remove duplicate SESSION_EXPIRATION_SECONDS (keep in response_analyzer.sh)
- Add clarifying comments for RALPH_SESSION_FILE vs CLAUDE_SESSION_FILE
All 265 tests pass.
- Fix BSD date parsing to handle milliseconds in ISO timestamps
(e.g., 2026-01-09T10:30:00.123+00:00)
- Document error_count mapping behavior when only has_errors=true is present
- Remove unused has_session_id_field variable
- Add debug logging for session persistence (controlled by VERBOSE_PROGRESS)
- Standardize session filename to .claude_session_id across all files
All 239 tests passing.
- Extend parse_json_response() to support both flat and Claude CLI formats
- Extract result, sessionId, and metadata fields
- Support metadata.files_changed, metadata.has_errors, completion_status
- Parse progress_indicators array for confidence boosting
- Add session management functions for continuity tracking:
- store_session_id(): Persist session with ISO timestamp
- get_last_session_id(): Retrieve stored session ID
- should_resume_session(): Check session validity (24-hour expiration)
- Add get_epoch_seconds() to date_utils.sh for cross-platform epoch time
- Auto-persist sessionId to .session_id file during response analysis
- Add 16 new TDD tests for Claude CLI format and session management
- Update documentation for v0.9.6 (239 tests total)
Test count: 239 (up from 223)
- Remove unused 'load mocks' (mocks.bash not needed)
- Use GIT_AUTHOR_*/GIT_COMMITTER_* env vars instead of git config --global
- Prefix git commands with 'command' to bypass shell function overrides
- Fix tautological assertions in edge case tests:
- Rename test to "succeeds when run in existing directory (idempotent)"
- Assert success ($status -eq 0) instead of always-true condition
README.md:
- Update version badge to v0.9.3
- Update test count to 165 in all locations
- Update test coverage breakdown (111 unit + 54 integration)
test_installation.bats:
- Add missing mock setup.sh in setup() function
- Fix dependency test to mock all three deps (jq, git, node/npx)
- Remove unused source_install_functions helper function
- Add test_installation.bats with full coverage of install.sh
- Tests cover directory creation, command installation, permissions
- Template and lib file copying verification
- Dependency detection with mocked failures (jq, git, node)
- PATH detection and warning system tests
- Uninstallation cleanup verification
- Idempotency testing (run twice without errors)
- End-to-end installation workflow validation
- All tests use isolated temp directories for safety
- Update CLAUDE.md with new test count (165 total)
- Fix npm test script to run tests recursively
- Version bump to v0.9.3
The build_claude_command() function was incorrectly using --prompt-file
which doesn't exist in Claude Code CLI. This fix:
- Replaces --prompt-file with -p flag plus prompt content
- Reads prompt content via $(cat "$prompt_file") before execution
- Adds error handling for missing prompt files
- Maintains shell injection safety through array-based command building
- Updates comments to reflect the correct approach
Adds 6 TDD tests verifying the fix:
- Uses -p flag instead of --prompt-file
- Reads prompt file content correctly
- Handles missing prompt file
- Includes all modern CLI flags
- Handles multiline prompt content
- Prevents shell injection
Test count: 145 -> 151 (all passing)