Skip to content

Conversation

@frankbria
Copy link
Owner

@frankbria frankbria commented Jan 21, 2026

Summary

  • Moves all Ralph-specific files into a hidden .ralph/ directory while keeping src/ at the project root
  • Improves compatibility with existing tooling (linters, IDEs) by reducing clutter in project root
  • Adds ralph-migrate command to upgrade existing projects

Changes

New Project Structure

project/
├── .ralph/                 # Ralph configuration (hidden folder)
│   ├── PROMPT.md
│   ├── @fix_plan.md
│   ├── @AGENT.md
│   ├── specs/
│   ├── logs/
│   └── docs/generated/
└── src/                    # Source code (at project root)

Files Modified

  • Core scripts: ralph_loop.sh, setup.sh, ralph_import.sh
  • Library scripts: lib/circuit_breaker.sh, lib/response_analyzer.sh
  • Install system: install.sh (added ralph-migrate command)
  • Templates: templates/PROMPT.md, templates/AGENT.md
  • Tests: All 11 test files updated for new paths
  • Documentation: README.md, CLAUDE.md

New Files

  • migrate_to_ralph_folder.sh - Migration script for existing projects

Breaking Change

Ralph configuration files now live in .ralph/ subfolder instead of project root.

Migration: Run ralph-migrate in existing projects to upgrade automatically.

Test plan

  • All 310 tests pass (100% pass rate)
  • Installation tests verify ralph-migrate command
  • Setup tests verify .ralph/ directory structure
  • Migration script tested with backup creation

Summary by CodeRabbit

  • New Features

    • Introduced a hidden .ralph/ directory to centralize prompts, plans, specs, state and logs.
    • Added migration tooling and a ralph-migrate command (and related import/migrate helpers).
  • Chores

    • Updated installers, setup, import, runtime and CI docs/tools to use the .ralph/ layout by default.
    • Updated uninstall behavior to remove migration wrapper.
  • Tests

    • Updated test suites and helpers to operate with the .ralph/ project layout.
  • Breaking Changes

    • Migration guidance and notes added; existing projects should run the migration.

✏️ Tip: You can customize this high-level summary in your review settings.

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).
@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Moves Ralph project state, configs, logs, prompts, and templates into a hidden .ralph/ subdirectory, updates scripts, installers, libraries, and tests to use that layout, and adds a ralph-migrate wrapper plus migrate_to_ralph_folder.sh to migrate existing projects. (30 words)

Changes

Cohort / File(s) Summary
Installer & Setup
install.sh, setup.sh, install_scripts/*
Installer and setup now create/use .ralph/ for templates, specs, logs, docs; adds ralph-migrate wrapper and installs migrate_to_ralph_folder.sh.
Migration tool
migrate_to_ralph_folder.sh, install_scripts/migrate_to_ralph_folder.sh
New migration script with prechecks, backup (.ralph_backup_<ts>), and relocation of PROMPT.md, @fix_plan.md, @AGENT.md, specs/, logs/, and hidden state into .ralph/.
Runtime loop & import
ralph_loop.sh, ralph_import.sh
Loop and import scripts updated to read/write prompts, sessions, status, exit signals, and analysis artifacts under .ralph/; messaging and path checks updated.
Core libs
lib/response_analyzer.sh, lib/circuit_breaker.sh
Introduced RALPH_DIR (default .ralph); updated default file paths and function defaults (e.g., parse_json_response, analyze_response, update_exit_signals, log_analysis_summary, detect_stuck_loop) to $RALPH_DIR/....
Templates & docs
templates/*, CLAUDE.md, README.md
Docs and templates updated to reference .ralph/ layout, migration guidance, updated examples, and new CLI wrappers (ralph-migrate, ralph-import).
Tests: fixtures & helpers
tests/helpers/fixtures.bash, tests/helpers/test_helper.bash
Test project creation and helpers updated to create .ralph/ and place mock PROMPT.md, @fix_plan.md, @AGENT.md, and state files there; added fail() helper and RALPH_DIR handling.
Tests: integration
tests/integration/*.bats (edge_cases, installation, loop_execution, prd_import, project_setup, ...)
Integration tests set RALPH_DIR=".ralph" and assert artifacts under .ralph/; installation tests validate ralph-migrate and migrate script presence.
Tests: unit
tests/unit/*.bats (cli_modern, cli_parsing, exit_detection, json_parsing, rate_limiting, session_continuity, ...)
Unit tests updated to derive and assert file paths from $RALPH_DIR (e.g., .response_analysis, .exit_signals, .call_count).
Misc
.gitignore, .claude/settings.local.json, create_files.sh
Updated ignore rules for .ralph/ artifacts, added permission whitelist Bash(node_modules/.bin/bats:*), and standardized create scripts to use .ralph/.

Sequence Diagram(s)

sequenceDiagram
  participant User as User (CLI)
  participant Installer as Installer/Wrapper
  participant Migrator as migrate_to_ralph_folder.sh
  participant FS as Filesystem
  participant App as Ralph scripts/libs

  User->>Installer: run `ralph-migrate` or installer
  Installer->>Migrator: invoke migrate script (from $RALPH_HOME)
  Migrator->>FS: check migration state
  alt needs migration
    Migrator->>FS: create backup (.ralph_backup_<ts>)
    Migrator->>FS: create `.ralph/` layout
    Migrator->>FS: move/copy PROMPT.md, `@fix_plan.md`, `@AGENT.md`, specs, logs, hidden state -> `.ralph/`
    Migrator->>User: print summary & next steps
  else already migrated
    Migrator->>User: report already migrated
  end
  User->>App: run `ralph` / `ralph-loop`
  App->>FS: read/write state under `.ralph/` (session, analysis, logs, status)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Poem

🐰
I hop and tuck the files away,
A hidden burrow named .ralph/ today,
I pack PROMPT, plans, and logs with care,
Backups snug, migrations fare,
Rabbit code rejoices — tidy lair! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.60% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: migrating Ralph files to a .ralph/ subfolder, which is the primary objective of this PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/ralph-subfolder-structure

Comment @coderabbitai help to get the list of available commands and usage tips.

@macroscopeapp
Copy link
Contributor

macroscopeapp bot commented Jan 21, 2026

Migrate all Ralph runtime, state, and templates to the .ralph subfolder and add a ralph-migrate command across CLI, scripts, and tests

Move configuration, session, logs, docs, circuit breaker, and analyzer artifacts to .ralph/; add ralph-migrate and pre-run migration checks; update project setup, import, and installer to the new layout; refactor default paths in lib/response_analyzer.sh, lib/circuit_breaker.sh, and ralph_loop.sh; update templates, .gitignore, and documentation; and realign unit/integration tests to .ralph/.

📍Where to Start

Start with the migration gate and new defaults in ralph_loop.sh, then review path changes in lib/response_analyzer.sh and lib/circuit_breaker.sh. Next, scan the migration script in migrate_to_ralph_folder.sh and the installer updates in install.sh.


Macroscope summarized f4f2880.

Comment on lines +232 to +239
has_completion_signal=$(jq -r '.has_completion_signal' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
exit_signal=$(jq -r '.exit_signal' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
is_test_only=$(jq -r '.is_test_only' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
is_stuck=$(jq -r '.is_stuck' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
work_summary=$(jq -r '.summary' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "")
files_modified=$(jq -r '.files_modified' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "0")
local json_confidence=$(jq -r '.confidence' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "0")
local session_id=$(jq -r '.session_id' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unquoted file paths in jq at lines 232–239 can split when RALPH_DIR has spaces, breaking reads. Consider quoting the path (e.g., "$RALPH_DIR/.json_parse_result") for safety and consistency.

Suggested change
has_completion_signal=$(jq -r '.has_completion_signal' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
exit_signal=$(jq -r '.exit_signal' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
is_test_only=$(jq -r '.is_test_only' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
is_stuck=$(jq -r '.is_stuck' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "false")
work_summary=$(jq -r '.summary' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "")
files_modified=$(jq -r '.files_modified' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "0")
local json_confidence=$(jq -r '.confidence' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "0")
local session_id=$(jq -r '.session_id' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "")
has_completion_signal=$(jq -r '.has_completion_signal' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "false")
exit_signal=$(jq -r '.exit_signal' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "false")
is_test_only=$(jq -r '.is_test_only' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "false")
is_stuck=$(jq -r '.is_stuck' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "false")
work_summary=$(jq -r '.summary' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "")
files_modified=$(jq -r '.files_modified' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "0")
local json_confidence=$(jq -r '.confidence' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "0")
local session_id=$(jq -r '.session_id' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "")

🚀 Want me to fix this? Reply ex: "fix it for me".

local project_dir="${1:-.}"

# Convert to absolute path
project_dir=$(cd "$project_dir" && pwd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Operations assume directories exist; under set -e a failing cd or file write can exit silently. Consider ensuring the directory exists and logging a clear message before using it.

Suggested change
project_dir=$(cd "$project_dir" && pwd)
if [[ ! -d "$project_dir" ]]; then
log "ERROR" "Project directory not found: $project_dir"
exit 1
fi
project_dir=$(cd "$project_dir" && pwd)

🚀 Want me to fix this? Reply ex: "fix it for me".

[[ -f "$project_dir/.circuit_breaker_history" ]] && cp "$project_dir/.circuit_breaker_history" "$backup_dir/"
[[ -f "$project_dir/.claude_session_id" ]] && cp "$project_dir/.claude_session_id" "$backup_dir/"
[[ -f "$project_dir/.ralph_session" ]] && cp "$project_dir/.ralph_session" "$backup_dir/"
[[ -f "$project_dir/status.json" ]] && cp "$project_dir/status.json" "$backup_dir/"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hidden files are being skipped during copy/backup, so dotfiles can be lost when sources are removed. Consider copying/archiving in a way that includes dotfiles (and include .ralph_* files in backups) to avoid data loss.

+    [[ -f "$project_dir/.ralph_session_history" ]] && cp "$project_dir/.ralph_session_history" "$backup_dir/"
+    [[ -f "$project_dir/.json_parse_result" ]] && cp "$project_dir/.json_parse_result" "$backup_dir/"
+    [[ -f "$project_dir/.last_output_length" ]] && cp "$project_dir/.last_output_length" "$backup_dir/"

🚀 Want me to fix this? Reply ex: "fix it for me".

@github-actions
Copy link

Code Review: PR #109 - Migrate Ralph files to .ralph/ subfolder

Summary

Well-structured breaking change that moves Ralph configuration files to a dedicated subfolder while preserving at project root. This is a significant improvement for project organization and tooling compatibility.

✅ Strengths

1. Migration Script Quality

  • Comprehensive backup creation with timestamped backup directories ()
  • Intelligent migration detection - checks both old structure and already-migrated projects
  • Graceful handling of partial migrations and edge cases

2. Code Consistency

  • All 24 modified files consistently use paths
  • Library files use pattern for flexibility (, )
  • Updated to include command ()

3. Test Coverage

  • All 11 test files updated for new structure
  • Test helper properly sets up directory in test fixtures ()

4. Documentation

  • CLAUDE.md accurately documents new structure
  • Templates updated with correct paths
  • README.md mentions breaking change and migration command

⚠️ Minor Issues

1. Version Inconsistency

  • README.md shows version 0.9.9 badge
  • CLAUDE.md shows version v0.9.8
  • Recommendation: Update to v0.10.0 since this is a breaking change

2. Directory Edge Case (handled correctly, but worth documenting)
The migration script removes empty directory after moving :

This correctly fails silently if is not empty (e.g., when exists). However, this behavior could be documented in the migration help text for clarity.

🔒 Security

  • No security concerns identified
  • All file operations stay within project directory
  • Backup creation prevents data loss

📊 Performance

  • Migration uses then pattern which is acceptable for typical project sizes
  • No performance bottlenecks identified

✅ Recommendation

Approve with minor version bump - This is a well-executed breaking change that improves project structure. The migration path is clear, test coverage is comprehensive, and implementation is solid.

Suggested version: v0.10.0 (breaking change)

One optional enhancement: Consider adding a dry-run flag to for safer adoption.

@claude
Copy link

claude bot commented Jan 21, 2026

Code Review: Migration to .ralph/ Subfolder Structure

I've reviewed PR 109 which migrates Ralph configuration files to a hidden .ralph/ subfolder. This is a well-structured refactoring that improves project organization.

✅ Strengths

1. Excellent Migration Strategy

  • Automatic backup creation: migrate_to_ralph_folder.sh creates timestamped backups before migration (lines 68-95)
  • Idempotent design: The script correctly detects already-migrated projects and skips unnecessary work
  • Comprehensive file coverage: Migrates all Ralph files including hidden state files

2. Consistent Path Updates

  • All core scripts updated to use RALPH_DIR=.ralph consistently
  • Template files properly updated with new paths
  • Library components use RALPH_DIR variable with sensible defaults

3. Comprehensive Test Updates

  • All 11 test files updated for new structure
  • 310 tests reported passing (excellent coverage)
  • Test helpers properly adjusted for .ralph/ paths

4. Good Documentation

  • CLAUDE.md thoroughly updated with new structure
  • README.md reflects new paths
  • Migration script includes helpful usage documentation

⚠️ Issues Found

1. CRITICAL: create_files.sh Not Updated

File: create_files.sh (lines 21, 23, etc.)

This bootstrap script still uses the old flat structure. New users running it will get the old structure, creating confusion and requiring manual migration.

Fix Required: Update create_files.sh to create the .ralph/ structure from the start, or deprecate it in favor of setup.sh.

2. Migration Script: Edge Case Handling

File: migrate_to_ralph_folder.sh

Issue 2a: Directory merge logic (lines 129-133) uses silent failure with || true which could hide permission errors or symlink issues.

Recommendation: Add explicit error checking and logging when copy operations encounter issues.

Issue 2b: Missing validation after migration (post-line 185). The script doesn't verify that all expected files were successfully moved to .ralph/.

Recommendation: Add post-migration validation function to verify critical files exist in their new locations.

3. Documentation: Missing Migration Failure Recovery

File: CLAUDE.md, README.md

Issue: No guidance on what to do if migration fails mid-way.

Recommendation: Add troubleshooting section explaining how to restore from backup if migration fails.

4. Minor: Inconsistent Error Messaging

File: ralph_loop.sh (line 323)

Error message should reference .ralph/PROMPT.md for clarity instead of just PROMPT.md.

🔒 Security Considerations

✅ No security issues identified

  • Migration script uses proper quoting for paths with spaces
  • No shell injection vulnerabilities
  • Backup mechanism prevents data loss

🚀 Performance Considerations

✅ No performance concerns

  • Migration is a one-time operation
  • No impact on Ralph loop performance

📊 Test Coverage

✅ Strong test coverage (310 tests passing)

Recommendation: Add specific migration tests for edge cases like spaces in filenames, symlinks, and permission errors.

📋 Summary

Category Status Notes
Code Quality ✅ Good Well-structured, modular approach
Bug Risk ⚠️ Medium create_files.sh creates wrong structure
Security ✅ Safe No vulnerabilities found
Performance ✅ Good No concerns
Test Coverage ✅ Strong 310 tests passing, could add edge cases
Documentation ⚠️ Good Missing failure recovery guide

🎯 Required Changes (Before Merge)

  1. MUST FIX: Update or deprecate create_files.sh
  2. SHOULD FIX: Add migration verification function
  3. SHOULD ADD: Migration troubleshooting documentation

✅ Recommended Changes (Post-Merge)

  1. Add edge case tests for migration (spaces, symlinks, permissions)
  2. Add explicit error messages for migration failures
  3. Consider adding --dry-run flag to migration script

🎉 Overall Assessment

This is a well-executed refactoring that significantly improves Ralph's project structure. The .ralph/ subfolder approach reduces clutter and improves compatibility with existing tooling.

Recommendation: Approve with required fixes - Address create_files.sh inconsistency before merging.

Great work on maintaining test coverage and providing a smooth migration path!

@github-actions
Copy link

The comment has been posted successfully. The review identifies:

  1. Strengths: Comprehensive migration script, consistent code changes, full test coverage, and good documentation
  2. Minor issues: Version number inconsistency between README (0.9.9) and CLAUDE.md (0.9.8)
  3. Edge case: The docs/ directory handling (correctly implemented but could be better documented)
  4. Security: No concerns
  5. Performance: No issues

The PR is well-executed for a breaking change that improves project organization.

New%20session%20-%202026-01-21T03%3A27%3A42.069Z
opencode session  |  github run

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
tests/unit/test_session_continuity.bats (1)

18-42: Create the sample prompt in .ralph to match PROMPT_FILE.

PROMPT_FILE now points to .ralph/PROMPT.md, but create_sample_prompt still writes to the project root. This can desync test fixtures from the new layout.

🔧 Proposed fix
-    create_sample_prompt
+    create_sample_prompt "$PROMPT_FILE"
tests/unit/test_json_parsing.bats (1)

128-134: Inconsistent path: result_file should use $RALPH_DIR/.json_parse_result.

Per the AI summary, lib/response_analyzer.sh now defaults to writing to "$RALPH_DIR/.json_parse_result". However, this test checks for .json_parse_result at the root level. This mismatch will cause the test to fail when parse_json_response writes to the new location.

🔧 Proposed fix
     run parse_json_response "$output_file"
-    local result_file=".json_parse_result"
+    local result_file="$RALPH_DIR/.json_parse_result"
 
     # Should create result file with parsed values
     [[ -f "$result_file" ]] || skip "parse_json_response not yet implemented"

Apply similar changes to all other occurrences in this file (lines 149, 170, 191, 211, 232, 253, 275, 316, 484, 504, 527, 550, 577, 601, 627).

templates/PROMPT.md (1)

281-284: Inconsistent path reference: should include .ralph/ prefix.

Line 282 references @fix_plan.md without the .ralph/ prefix, which is inconsistent with the updated path references throughout the rest of the document.

📝 Proposed fix
 ## Current Task
-Follow `@fix_plan.md` and choose the most important item to implement next.
+Follow .ralph/@fix_plan.md and choose the most important item to implement next.
 Use your judgment to prioritize what will have the biggest impact on project progress.
tests/unit/test_cli_modern.bats (3)

220-240: Test creates file at wrong path — should use $RALPH_DIR/@fix_plan.md.

The test creates @fix_plan.md at the root, but build_loop_context (lines 96-97) reads from $RALPH_DIR/@fix_plan.md. This test will always report 0 remaining tasks because it's reading from a nonexistent file.

🐛 Proposed fix
 `@test` "build_loop_context counts remaining tasks from `@fix_plan.md`" {
     # Create fix plan with 7 incomplete tasks
-    cat > "@fix_plan.md" << 'EOF'
+    cat > "$RALPH_DIR/@fix_plan.md" << 'EOF'
 # Fix Plan
 - [x] Task 1 done

289-296: Test references wrong path for @fix_plan.md.

Similar to the previous issue, this test removes @fix_plan.md from the root but build_loop_context looks for it in $RALPH_DIR/@fix_plan.md.

🐛 Proposed fix
 `@test` "build_loop_context handles missing `@fix_plan.md` gracefully" {
-    rm -f "@fix_plan.md"
+    rm -f "$RALPH_DIR/@fix_plan.md"
 
     run build_loop_context 1

298-305: Test references wrong path for .response_analysis.

The test removes .response_analysis from the root, but build_loop_context reads from $RALPH_DIR/.response_analysis (line 108).

🐛 Proposed fix
 `@test` "build_loop_context handles missing .response_analysis gracefully" {
-    rm -f ".response_analysis"
+    rm -f "$RALPH_DIR/.response_analysis"
 
     run build_loop_context 1
ralph_loop.sh (1)

130-131: Comparison uses stale default value for PROMPT_FILE.

The condition compares against "PROMPT.md" but the new default is "$RALPH_DIR/PROMPT.md" (line 18). This means custom prompt files passed via --prompt will always be detected, but this condition will never match for the default case, potentially adding duplicate flags.

🐛 Proposed fix
-    if [[ "$PROMPT_FILE" != "PROMPT.md" ]]; then
+    if [[ "$PROMPT_FILE" != "$RALPH_DIR/PROMPT.md" ]]; then
         ralph_cmd="$ralph_cmd --prompt '$PROMPT_FILE'"
     fi
🤖 Fix all issues with AI agents
In `@migrate_to_ralph_folder.sh`:
- Around line 104-109: The script currently pre-creates the examples folder via
the mkdir -p "$project_dir/.ralph/examples" which causes the later
examples-migration logic to skip because it assumes absence of the target dir;
either remove that mkdir for ".ralph/examples" so the migration logic can create
it only when source examples exist, or change the migration condition to check
the existence of the source examples (not the target) before skipping; update
the block containing mkdir -p "$project_dir/.ralph/examples" or the examples
migration guard so the migration runs only when source examples are present.
- Around line 179-183: The migration condition for moving examples never fires
because .ralph/examples is always created earlier; update the if-check around
the move (the block that logs "Moving examples/ to .ralph/examples/" and calls
mv) to run when an examples directory exists and the target .ralph/examples
either does not exist OR is empty (i.e., check that "$project_dir/examples" is a
directory and that "$project_dir/.ralph/examples" is absent or contains no
files) so existing examples get migrated without clobbering preexisting content.

In `@setup.sh`:
- Around line 15-25: The template copy commands in setup.sh (cp
../templates/PROMPT.md, cp ../templates/fix_plan.md, cp ../templates/AGENT.md,
cp -r ../templates/specs/*) can fail silently if ../templates/ doesn't exist;
update setup.sh to first verify the templates directory exists (e.g., test -d
../templates) and if missing either print a clear error via echo and exit
non-zero or fallback to a known location, and only perform the cp operations
when the check succeeds so missing templates are detected instead of silently
ignored.
🧹 Nitpick comments (6)
CLAUDE.md (2)

226-241: Breaking change is documented, but could be more prominent.

The migration note at line 240 is helpful. Based on learnings, breaking changes should be documented prominently. Consider adding a "⚠️ Breaking Changes" section near the top of the document or in the "Recent Improvements" section to ensure users migrating from older versions notice this change.

📝 Suggested enhancement: Add prominent breaking change notice

Add to the "Recent Improvements" section:

 ## Recent Improvements

+### Project Structure Migration (v0.9.9) ⚠️ BREAKING CHANGE
+- Ralph configuration files now reside in `.ralph/` instead of project root
+- **Migration required**: Run `ralph-migrate` in existing projects
+- New projects created with `ralph-setup` use the new structure automatically
+- Benefits: Reduced root clutter, improved tooling compatibility
+
 ### Modern CLI for PRD Import (v0.9.8)

227-238: Add language specifier to fenced code block.

Static analysis flagged MD040: fenced code blocks should have a language specified.

📝 Proposed fix
-```
+```text
 project-name/
 ├── .ralph/                # Ralph configuration and state (hidden folder)
README.md (1)

429-443: Add language specifier to fenced code block.

The fenced code block at line 431 is missing a language specifier. While this is a documentation structure diagram rather than code, adding a specifier improves consistency and satisfies linting.

📝 Suggested fix
-```
+```text
 my-project/
 ├── .ralph/                 # Ralph configuration and state (hidden folder)
ralph_loop.sh (2)

334-351: Separate declaration and assignment for masked return values.

Shellcheck flags lines 335-336 because combining local with command substitution masks the return value. While the code handles empty values gracefully, separating declaration from assignment is a best practice.

♻️ Suggested improvement
     # 4. Check fix_plan.md for completion
     if [[ -f "$RALPH_DIR/@fix_plan.md" ]]; then
-        local total_items=$(grep -c "^- \[" "$RALPH_DIR/@fix_plan.md" 2>/dev/null)
-        local completed_items=$(grep -c "^- \[x\]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null)
+        local total_items
+        local completed_items
+        total_items=$(grep -c "^- \[" "$RALPH_DIR/@fix_plan.md" 2>/dev/null) || true
+        completed_items=$(grep -c "^- \[x\]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null) || true

448-467: Separate declaration and assignment in build_loop_context.

Similar to the previous issue, lines 449, 455, and 463 combine local with command substitution. While functioning correctly, separating them would follow shellcheck best practices.

♻️ Suggested improvement
     # Extract incomplete tasks from `@fix_plan.md`
     if [[ -f "$RALPH_DIR/@fix_plan.md" ]]; then
-        local incomplete_tasks=$(grep -c "^- \[ \]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null || echo "0")
+        local incomplete_tasks
+        incomplete_tasks=$(grep -c "^- \[ \]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null || echo "0")
         context+="Remaining tasks: ${incomplete_tasks}. "
     fi
 
     # Add circuit breaker state
     if [[ -f "$RALPH_DIR/.circuit_breaker_state" ]]; then
-        local cb_state=$(jq -r '.state // "UNKNOWN"' "$RALPH_DIR/.circuit_breaker_state" 2>/dev/null)
+        local cb_state
+        cb_state=$(jq -r '.state // "UNKNOWN"' "$RALPH_DIR/.circuit_breaker_state" 2>/dev/null)
lib/response_analyzer.sh (1)

230-239: Separate declaration and assignment for cleaner error handling.

Lines 238-239 combine local with jq command substitution. While the fallback || echo handles failures, separating declaration improves consistency with shellcheck recommendations.

♻️ Suggested improvement
-            local json_confidence=$(jq -r '.confidence' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "0")
-            local session_id=$(jq -r '.session_id' $RALPH_DIR/.json_parse_result 2>/dev/null || echo "")
+            local json_confidence
+            local session_id
+            json_confidence=$(jq -r '.confidence' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "0")
+            session_id=$(jq -r '.session_id' "$RALPH_DIR/.json_parse_result" 2>/dev/null || echo "")

Also note: the $RALPH_DIR references here should be quoted for consistency (though they work unquoted since the path contains no spaces).

@frankbria frankbria linked an issue Jan 21, 2026 that may be closed by this pull request
@github-actions
Copy link

Code Review: PR #109

I've reviewed this PR after considering all prior reviews. This is a well-executed breaking change, but there are a few additional issues to address.

🔴 Critical Issue

1. .gitignore Still References Old Paths (migrate_to_ralph_folder.sh:76-92)

The file still ignores files at the root level (e.g., , , , ), but these files are now in . While this doesn't break functionality, it means:

  • Old entries will never match any files (since files are in )
  • The directory itself is not ignored, so its contents (including state files) might accidentally be committed
  • New projects get a confusing with non-matching patterns

Recommendation: Update to reference the new paths:

Note: If is not part of the template copying process in /, this may need to be added to the template copying logic.

✅ Already Well-Handled (No Action Needed)

The following concerns from earlier reviews are already correctly implemented:

  1. Hidden files in backup (migrate_to_ralph_folder.sh:83-92): All hidden state files ARE backed up, including , , and ✓
  2. Comprehensive migration: All expected files are in the array (lines 157-170) ✓

🟡 Minor Enhancement Opportunity

2. Add Post-Migration Verification Function

The migration script doesn't verify that all critical files were successfully moved. Adding a verification step would catch migration failures early:

Call this after completes.

📊 Overall Assessment

Category Status Notes
Code Quality ✅ Good Well-structured migration script
Test Coverage ✅ Strong All test files updated for new structure
Breaking Change ✅ Well-Managed Migration path is clear and safe
Git Ignore ⚠️ Needs Update Still references old paths

🎯 Recommendations

Before Merge (Required):

  • Update to reference paths
  • Verify if needs to be added to template copying in /

Post-Merge (Enhancements):

  • Add post-migration verification function
  • Consider adding flag to migration script

The overall structure migration is well-executed with comprehensive test coverage. Addressing the issue will complete the migration properly.

@github-actions
Copy link

Posted comprehensive code review to PR #109: #109 (comment)

New%20session%20-%202026-01-21T03%3A51%3A23.728Z
opencode session  |  github run

@claude
Copy link

claude bot commented Jan 21, 2026

Follow-Up Review: Migration to .ralph/ Subfolder

I've reviewed the latest changes to PR 109. This follows up on my previous review from earlier today.

🔄 Status Update

✅ New Addition

  • Gitignore Update: Added .claude/settings.local.json to .gitignore (commit bb2fef2) - Good practice to exclude local Claude Code settings

⚠️ Critical Issue Still Outstanding

create_files.sh NOT Updated - This was flagged as a CRITICAL issue in my previous review and remains unaddressed.

Current Problem:

  • File: create_files.sh lines 21-24
  • Still references old flat structure: PROMPT_FILE="PROMPT.md", LOG_DIR="logs"
  • New users running this bootstrap script will get the OLD structure, then need to manually migrate
  • Creates confusion and poor user experience

Impact: HIGH - This is a bootstrap script that creates the entire Ralph system. It's inconsistent with the new .ralph/ structure introduced in this PR.

Recommended Fix Options:

  1. Update create_files.sh to generate .ralph/ structure from the start, OR
  2. Deprecate create_files.sh with a clear note directing users to setup.sh instead, OR
  3. Add auto-migration at the end of create_files.sh to move files to .ralph/

I recommend Option 1 (update the script) for consistency.

⚠️ Minor Issues from Previous Review

These are still present but less critical:

1. Missing Post-Migration Validation (migrate_to_ralph_folder.sh)

  • The migration script tells users to "verify" manually (line 224) but doesn't automate verification
  • Recommendation: Add a verify_migration() function that checks all expected files exist in .ralph/

2. Version Inconsistency

  • README.md shows v0.9.9 (line 5, badge)
  • CLAUDE.md shows v0.9.8 (line 9)
  • Minor issue but should be aligned

3. Silent Failure Handling (migrate_to_ralph_folder.sh lines 131, 140)

  • Using || true to suppress errors could hide permission/symlink issues
  • Consider explicit error logging instead

📊 Current Assessment

Category Status Change from Previous
Migration Script ✅ Good No change
Path Updates ✅ Good No change
Test Coverage ✅ Strong No change
Documentation ✅ Good No change
create_files.sh BROKEN Still not fixed
Version Consistency ⚠️ Minor No change

🎯 Recommendation

BLOCK MERGE until create_files.sh is updated or deprecated. This is a foundational script that will confuse new users if it creates the wrong structure.

The rest of the PR is excellent - comprehensive, well-tested, and properly documented. The .ralph/ subfolder design is a significant improvement. Just need to fix this one critical inconsistency.

📝 Suggested Next Steps

  1. Choose fix approach for create_files.sh (recommend updating to .ralph/ structure)
  2. Implement the fix
  3. Test that create_files.sh creates proper .ralph/ structure
  4. Optionally: Add automated verification to migration script
  5. Optionally: Align version numbers between README and CLAUDE.md

Once create_files.sh is fixed, this PR will be ready to merge.

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.
@github-actions
Copy link

Code Review: Migration to .ralph/ Subfolder Structure

I've reviewed this PR after considering all prior reviews. This is a well-executed breaking change with good migration strategy, but several critical issues remain unaddressed.

✅ Issues Fixed Since Previous Reviews

Great progress on the following:

  • test_session_continuity.bats - Now creates PROMPT.md in correct location (line 40)
  • templates/PROMPT.md - Now correctly references (line 282)
  • ralph_loop.sh - Fixed default path comparison to use (line 130)
  • setup.sh - Added template verification with clear error messages (lines 15-27)
  • migrate_to_ralph_folder.sh - Examples directory migration logic corrected (lines 178-189)

🔴 Critical Issues (Blockers)

1. create_files.sh Still Creates Old Structure

  • Lines 21-24: Still uses ,
  • This bootstrap script is incompatible with the new structure
  • New users running this will get the OLD structure, causing confusion
  • Recommendation: Either update create_files.sh to generate structure, or deprecate it with clear message directing users to

2. .gitignore References Wrong Paths

  • Lines 10-17: Still reference and at root level
  • These files are now in , so these patterns won't match
  • New projects get a confusing .gitignore with non-matching entries
  • Recommendation: Update to , , etc.

🟡 Minor Issues

3. Missing Post-Migration Validation

  • migrate_to_ralph_folder.sh tells users to "verify" manually (line 230)
  • No automated verification that critical files exist in after migration
  • Recommendation: Add function to check all expected files

4. Version Inconsistency

  • README.md shows v0.9.9 badge
  • CLAUDE.md shows v0.9.8
  • Should align to v0.10.0 for this breaking change

✅ Strengths

  • Comprehensive test coverage (310 tests passing)
  • Migration script includes backup creation with timestamps
  • Smart detection of already-migrated projects
  • Documentation thoroughly updated
  • Library components use flexible pattern

📊 Current Assessment

Category Status Notes
Core Migration ✅ Excellent Well-structured migration script
Path Updates ✅ Good Most paths correctly updated
Test Coverage ✅ Strong 310 tests passing
create_files.sh BROKEN Creates wrong structure
.gitignore WRONG References old paths
Documentation ✅ Good Thoroughly updated

🎯 Recommendation

BLOCK MERGE until:

  1. create_files.sh is updated or deprecated
  2. .gitignore references new paths

The rest of the PR is excellent with comprehensive testing and solid implementation. Fixing these two blockers will make this ready to merge.

Minor enhancements (post-merge):

  • Add post-migration verification function
  • Align version numbers
  • Add --dry-run flag to migration script

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
tests/unit/test_json_parsing.bats (2)

149-155: Inconsistent path: missing $RALPH_DIR prefix for .json_parse_result.

Line 128 correctly uses $RALPH_DIR/.json_parse_result, but this test and several others (lines 170, 191, 211, 232, 252, 275, 316, 484, 504, 527, 550, 577, 601, 627) use .json_parse_result without the $RALPH_DIR prefix. This inconsistency may cause tests to look in the wrong location.

🐛 Proposed fix
     run parse_json_response "$output_file"
-    local result_file=".json_parse_result"
+    local result_file="$RALPH_DIR/.json_parse_result"

Apply the same fix to the other affected tests.


674-678: Inconsistent path: session files should use $RALPH_DIR prefix.

The session management tests reference .claude_session_id directly instead of $RALPH_DIR/.claude_session_id. In test_session_continuity.bats, CLAUDE_SESSION_FILE is defined as $RALPH_DIR/.claude_session_id, so these tests should match.

🐛 Proposed fix for affected lines (674, 687, 695, 703, 715, 725, 734)
     # Session ID should be persisted for continuity
-    [[ -f ".claude_session_id" ]] || skip "Session persistence not yet implemented"
+    [[ -f "$RALPH_DIR/.claude_session_id" ]] || skip "Session persistence not yet implemented"
 
-    local stored_session=$(cat .claude_session_id)
+    local stored_session=$(cat "$RALPH_DIR/.claude_session_id")
ralph_loop.sh (1)

1206-1212: Help text shows incorrect file paths.

The file paths at lines 1209-1212 are missing the .ralph/ prefix. The actual paths are:

  • .ralph/.ralph_session
  • .ralph/.ralph_session_history
  • .ralph/.call_count
  • .ralph/.last_reset
📝 Suggested fix
 Files created:
     - $LOG_DIR/: All execution logs
     - $DOCS_DIR/: Generated documentation
     - $STATUS_FILE: Current status (JSON)
-    - .ralph_session: Session lifecycle tracking
-    - .ralph_session_history: Session transition history (last 50)
-    - .call_count: API call counter for rate limiting
-    - .last_reset: Timestamp of last rate limit reset
+    - $RALPH_SESSION_FILE: Session lifecycle tracking
+    - $RALPH_SESSION_HISTORY_FILE: Session transition history (last 50)
+    - $CALL_COUNT_FILE: API call counter for rate limiting
+    - $TIMESTAMP_FILE: Timestamp of last rate limit reset
♻️ Duplicate comments (1)
migrate_to_ralph_folder.sh (1)

68-95: Backup function missing some state files that get migrated.

The backup function (lines 84-92) doesn't include all state files that are later migrated by migrate_project. Specifically, .ralph_session_history, .json_parse_result, and .last_output_length are in the migration array (lines 165-167) but not backed up.

🐛 Proposed fix: Add missing files to backup
     [[ -f "$project_dir/.claude_session_id" ]] && cp "$project_dir/.claude_session_id" "$backup_dir/"
     [[ -f "$project_dir/.ralph_session" ]] && cp "$project_dir/.ralph_session" "$backup_dir/"
     [[ -f "$project_dir/status.json" ]] && cp "$project_dir/status.json" "$backup_dir/"
+    [[ -f "$project_dir/.ralph_session_history" ]] && cp "$project_dir/.ralph_session_history" "$backup_dir/"
+    [[ -f "$project_dir/.json_parse_result" ]] && cp "$project_dir/.json_parse_result" "$backup_dir/"
+    [[ -f "$project_dir/.last_output_length" ]] && cp "$project_dir/.last_output_length" "$backup_dir/"
 
     echo "$backup_dir"
 }
🧹 Nitpick comments (6)
setup.sh (1)

29-45: Consider validating additional required template files.

The script validates PROMPT.md exists but doesn't check for fix_plan.md and AGENT.md before copying. If these files are missing, the cp commands on lines 43-44 will fail.

♻️ Optional: Add validation for all required templates
 # Verify required template files exist
 if [[ ! -f "$TEMPLATES_DIR/PROMPT.md" ]]; then
     echo "❌ Error: Required template file PROMPT.md not found in $TEMPLATES_DIR"
     exit 1
 fi
+if [[ ! -f "$TEMPLATES_DIR/fix_plan.md" ]]; then
+    echo "❌ Error: Required template file fix_plan.md not found in $TEMPLATES_DIR"
+    exit 1
+fi
+if [[ ! -f "$TEMPLATES_DIR/AGENT.md" ]]; then
+    echo "❌ Error: Required template file AGENT.md not found in $TEMPLATES_DIR"
+    exit 1
+fi
migrate_to_ralph_folder.sh (2)

70-70: Static analysis: Declare and assign separately to avoid masking return values.

The local declaration combined with command substitution can mask a non-zero exit status from date.

♻️ Optional fix per SC2155
-    local backup_dir="$project_dir/.ralph_backup_$(date +%Y%m%d_%H%M%S)"
+    local backup_dir
+    backup_dir="$project_dir/.ralph_backup_$(date +%Y%m%d_%H%M%S)"

196-199: Add directory existence check before cd.

If the provided project directory doesn't exist, cd "$project_dir" will fail. With set -e, this exits silently without a helpful error message.

♻️ Proposed fix
 main() {
     local project_dir="${1:-.}"
 
+    # Verify project directory exists
+    if [[ ! -d "$project_dir" ]]; then
+        log "ERROR" "Project directory not found: $project_dir"
+        exit 1
+    fi
+
     # Convert to absolute path
     project_dir=$(cd "$project_dir" && pwd)
ralph_loop.sh (3)

27-27: Remove unused SLEEP_DURATION variable.

This variable is defined but never referenced anywhere in the script. If it's intended for future use, consider adding a comment indicating that; otherwise, remove it to reduce dead code.

🧹 Suggested removal
 CLAUDE_TIMEOUT_MINUTES=15  # Default: 15 minutes timeout for Claude Code execution
-SLEEP_DURATION=3600     # 1 hour in seconds
 CALL_COUNT_FILE="$RALPH_DIR/.call_count"

334-351: Separate declaration and assignment to avoid masking return values.

Per ShellCheck SC2155, combining local with command substitution masks the return value. While the code handles empty values on lines 339-340, separating declaration and assignment is a best practice.

♻️ Suggested fix
     # 4. Check fix_plan.md for completion
     if [[ -f "$RALPH_DIR/@fix_plan.md" ]]; then
-        local total_items=$(grep -c "^- \[" "$RALPH_DIR/@fix_plan.md" 2>/dev/null)
-        local completed_items=$(grep -c "^- \[x\]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null)
-
+        local total_items
+        local completed_items
+        total_items=$(grep -c "^- \[" "$RALPH_DIR/@fix_plan.md" 2>/dev/null) || true
+        completed_items=$(grep -c "^- \[x\]" "$RALPH_DIR/@fix_plan.md" 2>/dev/null) || true
+        
         # Handle case where grep returns no matches (exit code 1)
         [[ -z "$total_items" ]] && total_items=0
         [[ -z "$completed_items" ]] && completed_items=0

454-467: Separate declaration and assignment for cb_state and prev_summary.

Per ShellCheck SC2155, these variables should have declaration separated from assignment. Line 449 already handles this with || echo "0" fallback, but lines 455 and 463 could mask jq failures.

♻️ Suggested fix
     # Add circuit breaker state
     if [[ -f "$RALPH_DIR/.circuit_breaker_state" ]]; then
-        local cb_state=$(jq -r '.state // "UNKNOWN"' "$RALPH_DIR/.circuit_breaker_state" 2>/dev/null)
+        local cb_state
+        cb_state=$(jq -r '.state // "UNKNOWN"' "$RALPH_DIR/.circuit_breaker_state" 2>/dev/null) || cb_state="UNKNOWN"
         if [[ "$cb_state" != "CLOSED" && "$cb_state" != "null" && -n "$cb_state" ]]; then
             context+="Circuit breaker: ${cb_state}. "
         fi
     fi
 
     # Add previous loop summary (truncated)
     if [[ -f "$RESPONSE_ANALYSIS_FILE" ]]; then
-        local prev_summary=$(jq -r '.analysis.work_summary // ""' "$RESPONSE_ANALYSIS_FILE" 2>/dev/null | head -c 200)
+        local prev_summary
+        prev_summary=$(jq -r '.analysis.work_summary // ""' "$RESPONSE_ANALYSIS_FILE" 2>/dev/null | head -c 200) || prev_summary=""
         if [[ -n "$prev_summary" && "$prev_summary" != "null" ]]; then
             context+="Previous: ${prev_summary}"
         fi
     fi

@github-actions
Copy link

Code Review: Migration to .ralph/ Subfolder Structure

I've reviewed this PR after considering all prior reviews. This is a well-executed breaking change with good migration strategy, but several critical issues remain unaddressed.

Issues Fixed Since Previous Reviews

Great progress on the following:

  • test_session_continuity.bats - Now creates PROMPT.md in correct .ralph/ location (line 40)
  • templates/PROMPT.md - Now correctly references .ralph/@fix_plan.md (line 282)
  • ralph_loop.sh - Fixed default path comparison to use $RALPH_DIR/PROMPT.md (line 130)
  • setup.sh - Added template verification with clear error messages (lines 15-27)
  • migrate_to_ralph_folder.sh - Examples directory migration logic corrected (lines 178-189)

🔴 Critical Issues (Blockers)

1. create_files.sh Still Creates Old Structure

Lines 21-24 in create_files.sh still use the old flat structure:

  • PROMPT_FILE="PROMPT.md"
  • LOG_DIR="logs"

This bootstrap script is incompatible with the new .ralph/ structure. New users running this will get the OLD structure, then need to manually migrate, causing confusion and poor user experience.

Recommendation: Either update create_files.sh to generate .ralph/ structure, or deprecate it with a clear message directing users to setup.sh.

2. .gitignore References Wrong Paths

Lines 10-17 in .gitignore still reference paths at the root level:

  • logs/*
  • docs/generated/*

These files are now in .ralph/, so these patterns won't match. New projects get a confusing .gitignore with non-matching entries.

Recommendation: Update to .ralph/logs/*, .ralph/docs/generated/*, etc.

🟡 Minor Issues

3. Missing Post-Migration Validation

The migration script tells users to "verify" manually (line 230), but doesn't automate verification that all critical files exist in .ralph/ after migration.

Recommendation: Add a verify_migration() function to check all expected files exist in their new locations.

4. Version Inconsistency

  • README.md shows v0.9.9 badge (line 5)
  • CLAUDE.md shows v0.9.8 (line 9)

Recommendation: Align to v0.10.0 for this breaking change.

✅ Strengths

  • Comprehensive test coverage (310 tests passing)
  • Migration script includes backup creation with timestamps
  • Smart detection of already-migrated projects
  • Documentation thoroughly updated
  • Library components use flexible RALPH_DIR pattern

📊 Current Assessment

Category Status Notes
Core Migration ✅ Excellent Well-structured migration script
Path Updates ✅ Good Most paths correctly updated
Test Coverage ✅ Strong 310 tests passing
create_files.sh BROKEN Creates wrong structure
.gitignore WRONG References old paths
Documentation ✅ Good Thoroughly updated

🎯 Recommendation

BLOCK MERGE until:

  1. create_files.sh is updated or deprecated
  2. .gitignore references new .ralph/ paths

The rest of the PR is excellent with comprehensive testing and solid implementation. Fixing these two blockers will make this ready to merge.

Optional Enhancements (Post-Merge)

  • Add post-migration verification function
  • Align version numbers between README and CLAUDE.md
  • Add --dry-run flag to migration script
  • Add edge case tests for migration (spaces, symlinks, permissions)

Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
@github-actions
Copy link

Review posted: #109 (comment)

New%20session%20-%202026-01-21T06%3A02%3A27.259Z
opencode session  |  github run

@claude
Copy link

claude bot commented Jan 21, 2026

Code Review: PR 109 - .ralph/ Subfolder Migration (Third Review)

I've reviewed the latest changes including commit 90d1cd4. This PR makes significant progress on the .ralph/ migration, but critical issues remain that block merging.

CRITICAL ISSUES (Must Fix Before Merge)

Number 1. create_files.sh NOT Updated - HIGHEST PRIORITY

Status: NOT ADDRESSED

The bootstrap script create_files.sh still creates the OLD flat structure and contradicts the entire .ralph/ migration. This is a major user-facing regression because any user running ./create_files.sh gets an OLD-STYLE project structure.

Evidence:

  • Line 9: creates dirs at root, not in .ralph/
  • Line 21: PROMPT_FILE="PROMPT.md" should be .ralph/PROMPT.md
  • Lines 204-206: Checks @fix_plan.md at root
  • Lines 496-502: Embedded setup.sh template creates files at root
  • Lines 512-513: Instructions reference PROMPT.md not .ralph/PROMPT.md

Required fixes: All directory creation must use .ralph/ prefix, update all file paths, update embedded templates, update help text.

Number 2. .gitignore Still References Old Paths

Status: PARTIALLY FIXED BUT INCOMPLETE

The .gitignore was updated for session files but still has wrong paths for state files. According to ralph_loop.sh lines 18-21, files should be at .ralph/.call_count, .ralph/.last_reset, .ralph/.exit_signals, .ralph/status.json but .gitignore references them at root level.

Number 3. Version Number Inconsistency

Status: NOT FIXED

README.md shows v0.9.9 with 308 tests, but CLAUDE.md line 9 still shows v0.9.8 with 276 tests. These should be synchronized.

WHAT WAS FIXED (Great Progress!)

The latest commit 90d1cd4 fixed multiple path issues:

  • setup.sh - Correctly creates .ralph/ structure and copies templates
  • ralph_loop.sh - All paths use RALPH_DIR properly
  • templates/PROMPT.md - References .ralph/@fix_plan.md correctly
  • Test files - All updated for new paths
  • migrate_to_ralph_folder.sh - Well-designed migration with backups

Overall Assessment

This PR is approximately 75% complete. The migration design is excellent, but these critical inconsistencies will confuse users.

REQUIRED before merge:

  1. Update create_files.sh to use .ralph/ structure
  2. Fix .gitignore to add .ralph/ prefixes for state files
  3. Update CLAUDE.md version to v0.9.9 and test count to 308

RECOMMENDED enhancements:
4. Add verify_migration_success() function to migration script
5. Add explicit note in README about .ralph/ structure

Files requiring changes: create_files.sh, .gitignore, CLAUDE.md, optionally migrate_to_ralph_folder.sh

Consistency Note: This review builds on previous reviews from github-actions bot and claude bot. The create_files.sh issue was flagged in the previous review and remains unaddressed.

@github-actions
Copy link

Code Review: PR #109 - Final Verification

I've reviewed this PR after considering all prior reviews. The migration to subfolder is well-executed, but critical blockers remain that prevent merging.


🔴 CRITICAL ISSUES (Must Fix Before Merge)

1. create_files.sh Still Uses OLD Structure - HIGHEST PRIORITY ⚠️

File: (lines 9, 21-23, 496-502, 512-513)

This bootstrap script creates the OLD flat structure, contradicting the entire migration:

Evidence:

  • Line 9: - Creates directories at root

  • Lines 21-23: Sets old paths without prefix:

  • Lines 496-502: Embedded setup.sh creates files at root

  • Lines 512-513: Help text references old structure

Impact: Users running 🚀 Creating Ralph for Claude Code repository structure...
✅ All files created successfully!

📁 Repository structure:
├── ralph_loop.sh # Main Ralph loop
├── ralph_monitor.sh # Live monitoring
├── setup.sh # Project setup
├── templates/ # Template files
└── .gitignore # Git ignore rules

🚀 Next steps:

  1. git add .
  2. git commit -m 'Add Ralph for Claude Code implementation'
  3. git push origin main
  4. ./setup.sh my-first-project get an OLD-STYLE project that conflicts with Ralph's new architecture.

Required Fix: Update all directory creation and path references to use subfolder:

Alternative: Deprecate with clear message directing users to .


2. .gitignore References Wrong Paths

File: (lines 2-8, 11-16)

The is incomplete and partially incorrect:

State files (lines 2-8): References files at root level, but they're now in :

Directory patterns (lines 11-16): Correct conceptually but missing prefix:

Impact:

  • State files at root will never be matched (confusing)
  • Generated files may accidentally be committed if directory itself isn't ignored
  • New projects get a with non-matching patterns

Required Fix: Update to reference paths:


3. Version Number Inconsistency

Files: (line 5) vs (line 9)

  • README.md: Shows v0.9.9 with 308 tests passing
  • CLAUDE.md: Shows v0.9.8 with 276 tests passing

Recommendation: Align to v0.10.0 for this breaking change and update test count to 308.


✅ What's Working Well

  1. Migration Script () - Excellent design with:

    • Backup creation before migration (lines 68-95)
    • Idempotent detection (lines 40-65)
    • Comprehensive file coverage (lines 156-169)
    • Clear help documentation (lines 237-282)
  2. Core Scripts Updated - All 24 modified files consistently use

  3. Test Coverage - All 11 test files updated for new structure, 308 tests passing

  4. Documentation - CLAUDE.md thoroughly documents the new structure


🟡 Minor Issues (Post-Merge)

4. Missing Post-Migration Verification

File: (line 230)

The script tells users to manually verify but doesn't automate it. Adding a function would catch failures early:

Call this after completes.


📊 Final Assessment

Category Status Notes
Core Migration ✅ Excellent Well-designed migration script
Path Updates ✅ Good Most paths correctly updated
Test Coverage ✅ Strong 308 tests passing
create_files.sh BROKEN Creates wrong structure
.gitignore WRONG References old paths
Documentation ✅ Good Thoroughly updated
Version Numbers ⚠️ Inconsistent Should align to v0.10.0

🎯 Recommendation

BLOCK MERGE until:

  1. ✅ is updated or deprecated
  2. ✅ references new paths
  3. ✅ Version numbers aligned to v0.10.0

This PR is ~85% complete. The migration design is excellent, but these critical inconsistencies will confuse users and break the expected behavior.

The rest of the implementation - migration script, path updates, test coverage, and documentation - is solid and ready to merge.


📝 Suggested Fix Summary

create_files.sh: Update 12+ path references to use structure OR add deprecation notice.

.gitignore: Replace lines 2-16 with correct paths as shown above.

CLAUDE.md: Update line 9 to match README.md (v0.10.0, 308 tests).

Once these fixes are applied, this PR will be ready to merge.

@github-actions
Copy link

Author identity unknown

*** Please tell me who you are.

Run

git config --global user.email "[email protected]"
git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: empty ident name (for runner@runnervmmtnos.5h22ydpj3h3ejlrfk43sdsvwae.cx.internal.cloudapp.net) not allowed

opencode session  |  github run

@claude
Copy link

claude bot commented Jan 21, 2026

Code Review - PR Number 109

This PR implements a well-designed architectural improvement moving Ralph files into a hidden .ralph/ directory.

Strengths

  • Excellent migration script with automatic backups and idempotency checks
  • All 11 test files properly updated for new paths
  • 310 tests passing (100% pass rate)
  • Comprehensive documentation updates in CLAUDE.md and README.md
  • Good user experience with clear logging

Critical Issue: .gitignore Missing Entries

The PR adds .claude/settings.local.json but is missing .gitignore entries for Ralph runtime state files that should not be committed:

.ralph/.call_count
.ralph/.last_reset
.ralph/.exit_signals
.ralph/.response_analysis
.ralph/.circuit_breaker_state
.ralph/.circuit_breaker_history
.ralph/.claude_session_id
.ralph/.ralph_session
.ralph/.ralph_session_history
.ralph/status.json
.ralph/logs/

Migration Script Issues

migrate_to_ralph_folder.sh lines 130-132, 138-141, 147-150 use || true which silently swallows copy errors. Users won't know if migration failed.

Recommendation: Replace with proper error logging like:
if ! cp -r src dest 2>/dev/null; then log WARN "Copy failed"; fi

Breaking Change Handling

Add detection in ralph_loop.sh to guide users with old structure:
if [[ -f PROMPT.md ]] && [[ ! -d .ralph ]]; then echo "ERROR: Run ralph-migrate to upgrade"; exit 1; fi

Minor Inconsistencies

  • setup.sh always creates examples/ but migration only moves it conditionally
  • Need migration guide documentation

Overall Assessment

Approve with required changes above

Excellent architectural improvement with strong migration tooling. The .gitignore and error handling issues should be fixed before merge.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@migrate_to_ralph_folder.sh`:
- Line 70: The combined declaration+command-substitution "local
backup_dir=\"$project_dir/.ralph_backup_$(date +%Y%m%d_%H%M%S)\"" masks the exit
status of date; change this in migrate_to_ralph_folder.sh by declaring the
variable first (local backup_dir) then run the date into a separate variable
(e.g. backup_ts="$(date +%Y%m%d_%H%M%S")" and check its exit status (or guard
with || exit/return) before assigning
backup_dir="$project_dir/.ralph_backup_${backup_ts}"; reference the symbols
backup_dir and project_dir and ensure you handle date failure appropriately.
- Around line 129-132: The current copy command uses a glob
("$project_dir/specs"/*) which skips dotfiles and also swallows errors with "||
true", risking data loss when "rm -rf $project_dir/specs" runs; change the copy
to preserve dotfiles and attributes (e.g., use the "cp -a source/. dest/"
pattern or rsync) targeting "$project_dir/specs" -> "$project_dir/.ralph/specs",
remove the "|| true" so failures surface, and only run the removal of
"$project_dir/specs" if the copy returned success (check the cp/rsync exit
status) to avoid deleting files on partial failure; reference the existing
variables/paths project_dir, specs, .ralph/specs, and the rm -rf invocation when
making the fix.
♻️ Duplicate comments (2)
migrate_to_ralph_folder.sh (2)

196-199: Validate directory existence before path resolution.

Under set -e, if the user provides a non-existent directory, cd "$project_dir" fails silently without a helpful error message. Add validation before the path resolution.

🐛 Proposed fix
     local project_dir="${1:-.}"
 
+    # Validate directory exists
+    if [[ ! -d "$project_dir" ]]; then
+        log "ERROR" "Project directory not found: $project_dir"
+        exit 1
+    fi
+
     # Convert to absolute path
     project_dir=$(cd "$project_dir" && pwd)

83-92: Backup missing some state files that will be migrated.

The state_files array in migrate_project() (lines 156-169) includes .ralph_session_history, .json_parse_result, and .last_output_length, but these are not backed up here. If migration fails after moving these files, they could be lost.

🐛 Proposed fix: Add missing state files to backup
     [[ -f "$project_dir/.ralph_session" ]] && cp "$project_dir/.ralph_session" "$backup_dir/"
+    [[ -f "$project_dir/.ralph_session_history" ]] && cp "$project_dir/.ralph_session_history" "$backup_dir/"
+    [[ -f "$project_dir/.json_parse_result" ]] && cp "$project_dir/.json_parse_result" "$backup_dir/"
+    [[ -f "$project_dir/.last_output_length" ]] && cp "$project_dir/.last_output_length" "$backup_dir/"
     [[ -f "$project_dir/status.json" ]] && cp "$project_dir/status.json" "$backup_dir/"

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.
@github-actions
Copy link

Code Review Summary: PR #109

This PR implements a well-designed architectural improvement moving Ralph configuration files to a hidden subfolder. The migration strategy is excellent, and most components have been properly updated. However, critical blockers remain that prevent merging.


🔴 Critical Issues (Must Fix Before Merge)

1. create_files.sh Creates OLD Structure - BLOCKER

Status: NOT ADDRESSED despite multiple reviews flagging this

The bootstrap script creates the OLD flat structure, contradicting the entire migration:

Evidence (lines 9, 21-23, 496-502):

Impact: Users running 🚀 Creating Ralph for Claude Code repository structure...
✅ All files created successfully!

📁 Repository structure:
├── ralph_loop.sh # Main Ralph loop
├── ralph_monitor.sh # Live monitoring
├── setup.sh # Project setup
├── templates/ # Template files
└── .gitignore # Git ignore rules

🚀 Next steps:

  1. git add .
  2. git commit -m 'Add Ralph for Claude Code implementation'
  3. git push origin main
  4. ./setup.sh my-first-project get an OLD-STYLE project that conflicts with Ralph's new architecture, requiring manual migration.

Required Fix: Update all path references to use subfolder OR deprecate with clear message directing users to .


2. .gitignore Still References Old Paths

Status: PARTIALLY FIXED - Updated for session files but missing state file paths

The needs comprehensive updates for the new structure. Per lines 18-21, files should be at , , etc., but references root-level paths.

Current .gitignore (lines 2-8):

Impact: State files at root will never be matched (confusing), and directory contents may accidentally be committed.

Required Fix: Update to reference paths comprehensively.


3. Version Inconsistency

Status: NOT FIXED

  • : Shows v0.9.9 with 308 tests
  • : Shows v0.9.8 with 276 tests

Recommendation: Align to v0.10.0 for this breaking change.


✅ What's Working Well

  1. Migration Script () - Excellent design with backups, idempotency, and comprehensive file coverage
  2. Core Scripts - All 24 modified files consistently use
  3. Test Coverage - All 11 test files updated, 308 tests passing
  4. Documentation - CLAUDE.md thoroughly documents new structure

🟡 Minor Issues (Post-Merge)

  1. Missing post-migration verification function to check all critical files exist after migration
  2. ShellCheck SC2155 warnings on + command substitution patterns (e.g., )
  3. Some test paths still need prefix updates (e.g., lines 149, 170, 191, etc.)

📊 Current Assessment

Category Status Notes
Core Migration ✅ Excellent Well-designed migration script
Path Updates ✅ Good Most paths correctly updated
Test Coverage ✅ Strong 308 tests passing
create_files.sh BROKEN Creates wrong structure
.gitignore INCOMPLETE Missing prefixes
Documentation ✅ Good Thoroughly updated
Version Numbers ⚠️ Inconsistent Should align to v0.10.0

🎯 Recommendation

BLOCK MERGE until:

  1. ✅ is updated or deprecated
  2. ✅ references new paths
  3. ✅ Version numbers aligned to v0.10.0

This PR is ~85% complete. The migration design is excellent, but these critical inconsistencies will confuse users and break expected behavior. Once the two blockers are fixed, this will be ready to merge.


Files requiring changes: , ,

This review synthesizes findings from multiple prior reviews by github-actions, coderabbitai, macroscopeapp, and claude. The and issues have been consistently flagged as critical blockers across all previous reviews.

@github-actions
Copy link

Author identity unknown

*** Please tell me who you are.

Run

git config --global user.email "[email protected]"
git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: empty ident name (for runner@runnervmmtnos.5gwla1swo3surccstcunnuqdtg.yx.internal.cloudapp.net) not allowed

opencode session  |  github run

# - All Ralph-specific files go in .ralph/ subfolder
mkdir -p src
mkdir -p .ralph/{specs/stdlib,examples,logs,docs/generated}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.gitignore expects !.ralph/logs/.gitkeep and !.ralph/docs/generated/.gitkeep, but setup.sh doesn’t create them, so empty dirs won’t be tracked. Consider creating these .gitkeep files in setup.sh after the directories are made.

+touch .ralph/logs/.gitkeep
+touch .ralph/docs/generated/.gitkeep

🚀 Want me to fix this? Reply ex: "fix it for me".

@claude
Copy link

claude bot commented Jan 21, 2026

Code Review: PR 109 - Migration to .ralph/ Subfolder

I've reviewed this PR after considering all prior reviews. This PR successfully addresses the major concerns raised in previous reviews.

Summary

This is a well-executed breaking change that migrates Ralph configuration files from the project root to a hidden .ralph/ directory. The implementation is comprehensive and production-ready.

Strengths

1. Migration Script Quality (migrate_to_ralph_folder.sh)

  • Proper error handling for timestamp generation (lines 73-77)
  • Fail-safe copy pattern using cp -a source/. dest/ (lines 138-143, 153-158, 168-175)
  • Verify copy success before deletion - prevents data loss
  • Comprehensive backup creation before migration
  • Clear user feedback with logging

2. Previous Issues Resolved

  • .gitignore now correctly references .ralph/ paths (lines 1-19)
  • create_files.sh updated to use .ralph/ structure (line 504)
  • Version numbers aligned to v0.10.0 throughout
  • All 310 tests passing (100% pass rate)

3. Code Quality

  • Consistent path updates across all 11 test files
  • Library scripts (circuit_breaker.sh, response_analyzer.sh) updated
  • Comprehensive documentation updates in CLAUDE.md and README.md
  • Idempotency checks prevent double migration

Remaining Issues from CodeRabbit

1. Backup Missing Three State Files (lines 93-101)

The backup function does not include these files that will be migrated:

  • .ralph_session_history
  • .json_parse_result
  • .last_output_length

Recommendation: Add these three files to the backup in create_backup() function.

2. Missing Directory Validation (line 232)

Under set -e, if user provides a non-existent directory, cd fails without a helpful error message.

Recommendation: Add validation before path resolution to check if directory exists.

Performance Considerations

  • Migration script is fast and efficient
  • No performance regressions in core Ralph loop
  • Backup creation adds ~1-2 seconds (acceptable for one-time migration)

Security Considerations

  • No security vulnerabilities introduced
  • .gitignore properly excludes sensitive state files
  • Backup creation prevents accidental data loss

Test Coverage

  • 310 tests passing (100% pass rate)
  • All test files updated for new paths
  • Installation tests verify ralph-migrate command
  • Setup tests verify .ralph/ directory structure

Breaking Change Assessment

Impact: HIGH - All existing Ralph projects need migration

Mitigation: EXCELLENT

  • Auto-detection of old structure with clear error messages
  • ralph-migrate command for easy upgrade
  • Comprehensive backup before migration
  • Clear migration guide in documentation

Recommendation

APPROVE with minor improvements

The two issues above are nice-to-haves that improve error handling but don't block merge. The migration design is solid, implementation is thorough, and all critical previous review feedback has been addressed.

This PR represents a significant architectural improvement that will benefit long-term maintainability.

Files Reviewed

  • migrate_to_ralph_folder.sh (migration script)
  • .gitignore (path updates)
  • create_files.sh (directory structure)
  • CLAUDE.md (documentation)
  • ralph_loop.sh, setup.sh, ralph_import.sh (core scripts)
  • lib/circuit_breaker.sh, lib/response_analyzer.sh (library components)
  • All 11 test files in tests/ directory

@frankbria frankbria merged commit 9b19d70 into main Jan 21, 2026
8 of 9 checks passed
@frankbria frankbria deleted the feature/ralph-subfolder-structure branch January 21, 2026 06:22
@kyych
Copy link

kyych commented Jan 21, 2026

https://github.com/frankbria/ralph-claude-code/blob/main/ralph_monitor.sh#L7 The old log location is still in use in ralph-monitor

aparosa2001 added a commit to aparosa2001/ralph-claude-code that referenced this pull request Jan 21, 2026
The ralph_monitor.sh script was still using the old log path 'logs/ralph.log'
instead of the new v0.10.0 structure '.ralph/logs/ralph.log'.

This caused the monitor to show outdated logs when Ralph was running with
the new directory structure.

Changes:
- Update LOG_FILE from 'logs/ralph.log' to '.ralph/logs/ralph.log'
- Aligns with v0.10.0 directory structure (PR frankbria#109)

Fixes: Monitor displaying old/incorrect logs
Related: frankbria#109 (feat: migrate Ralph files to .ralph/ subfolder)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move Ralph project files to a .ralph subfolder to avoid conflicts

3 participants