Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

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.

**Version**: v0.11.1 | **Tests**: 424 passing (100% pass rate) | **CI/CD**: GitHub Actions
**Version**: v0.11.2 | **Tests**: 440 passing (100% pass rate) | **CI/CD**: GitHub Actions

## Core Architecture

Expand Down Expand Up @@ -205,7 +205,7 @@ Ralph uses modern Claude Code CLI flags for structured communication:
**Configuration Variables:**
```bash
CLAUDE_OUTPUT_FORMAT="json" # Output format: json (default) or text
CLAUDE_ALLOWED_TOOLS="Write,Bash(git *),Read" # Allowed tool permissions
CLAUDE_ALLOWED_TOOLS="Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)" # Allowed tool permissions
CLAUDE_USE_CONTINUE=true # Enable session continuity
CLAUDE_MIN_VERSION="2.0.76" # Minimum Claude CLI version
```
Expand Down Expand Up @@ -436,6 +436,13 @@ bats tests/unit/test_cli_parsing.bats

## Recent Improvements

### Setup Permissions Fix (v0.11.2)
- Fixed issue #136: `ralph-setup` now creates `.ralphrc` with consistent tool permissions
- Updated default `ALLOWED_TOOLS` from `Write,Bash(git *),Read` to `Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)`
- Both `ralph-setup` and `ralph-enable` now create identical `.ralphrc` configurations
- Added 8 new TDD tests for `.ralphrc` creation and ALLOWED_TOOLS defaults
- Test count: 440 (up from 424)

### Completion Indicators Fix (v0.11.1)
- Fixed premature exit after exactly 5 loops in JSON output mode
- Root cause: `update_exit_signals()` used confidence threshold (≥60) to populate `completion_indicators`
Expand Down
231 changes: 133 additions & 98 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions ralph_loop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ CLAUDE_TIMEOUT_MINUTES="${CLAUDE_TIMEOUT_MINUTES:-15}"

# Modern Claude CLI configuration (Phase 1.1)
CLAUDE_OUTPUT_FORMAT="${CLAUDE_OUTPUT_FORMAT:-json}"
CLAUDE_ALLOWED_TOOLS="${CLAUDE_ALLOWED_TOOLS:-Write,Bash(git *),Read}"
CLAUDE_ALLOWED_TOOLS="${CLAUDE_ALLOWED_TOOLS:-Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)}"
CLAUDE_USE_CONTINUE="${CLAUDE_USE_CONTINUE:-true}"
CLAUDE_SESSION_FILE="$RALPH_DIR/.claude_session_id" # Session ID persistence file
CLAUDE_MIN_VERSION="2.0.76" # Minimum required Claude CLI version
Expand Down Expand Up @@ -217,7 +217,7 @@ setup_tmux_session() {
ralph_cmd="$ralph_cmd --timeout $CLAUDE_TIMEOUT_MINUTES"
fi
# Forward --allowed-tools if non-default
if [[ "$CLAUDE_ALLOWED_TOOLS" != "Write,Bash(git *),Read" ]]; then
if [[ "$CLAUDE_ALLOWED_TOOLS" != "Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)" ]]; then
ralph_cmd="$ralph_cmd --allowed-tools '$CLAUDE_ALLOWED_TOOLS'"
fi
# Forward --no-continue if session continuity disabled
Expand Down
48 changes: 48 additions & 0 deletions setup.sh

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Critical

Issue on line in setup.sh:7:

PROJECT_NAME from user input is interpolated unsanitized into the heredoc. When .ralphrc is later sourced, malicious input like test"; rm -rf ~; # executes arbitrary commands. Consider validating PROJECT_NAME at line 7 to reject characters like ", ;, `, $, or newlines.

-PROJECT_NAME=${1:-"my-project"}
+PROJECT_NAME=${1:-"my-project"}
+
+# Validate PROJECT_NAME to prevent command injection when .ralphrc is sourced
+if [[ ! "$PROJECT_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then
+    echo "❌ Error: PROJECT_NAME must contain only alphanumeric characters, hyphens, and underscores."
+    exit 1
+fi

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

Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ cd "$PROJECT_NAME"
# Determine templates directory location (checked AFTER cd into project)
# Check local ../templates first, then global ~/.ralph/templates
TEMPLATES_DIR=""
LIB_DIR=""
if [[ -d "../templates" ]]; then
TEMPLATES_DIR="../templates"
LIB_DIR="../lib"
elif [[ -d "$HOME/.ralph/templates" ]]; then
TEMPLATES_DIR="$HOME/.ralph/templates"
LIB_DIR="$HOME/.ralph/lib"
else
echo "❌ Error: Templates directory not found."
echo " Expected at: ../templates or ~/.ralph/templates"
Expand All @@ -44,6 +47,51 @@ cp "$TEMPLATES_DIR/fix_plan.md" .ralph/fix_plan.md
cp "$TEMPLATES_DIR/AGENT.md" .ralph/AGENT.md
cp -r "$TEMPLATES_DIR/specs"/* .ralph/specs/ 2>/dev/null || true

# Generate .ralphrc configuration file
# Source enable_core.sh if available for generate_ralphrc(), otherwise create inline
if [[ -f "$LIB_DIR/enable_core.sh" ]]; then
# Temporarily disable colors for cleaner output
export ENABLE_USE_COLORS=false
source "$LIB_DIR/enable_core.sh"
# Generate .ralphrc and fix the generator label (library says "ralph enable")
generate_ralphrc "$PROJECT_NAME" "generic" "local" | sed 's/Generated by: ralph enable/Generated by: ralph-setup/' > .ralphrc
else
Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Fallback: create minimal .ralphrc inline (same content as generate_ralphrc)
cat > .ralphrc << RALPHRCEOF
# .ralphrc - Ralph project configuration
# Generated by: ralph-setup
# Documentation: https://github.com/frankbria/ralph-claude-code

# Project identification
PROJECT_NAME="${PROJECT_NAME}"
PROJECT_TYPE="generic"

# Loop settings
MAX_CALLS_PER_HOUR=100
CLAUDE_TIMEOUT_MINUTES=15
CLAUDE_OUTPUT_FORMAT="json"

# Tool permissions
# Comma-separated list of allowed tools
ALLOWED_TOOLS="Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)"

# Session management
SESSION_CONTINUITY=true
SESSION_EXPIRY_HOURS=24

# Task sources (for ralph enable --sync)
# Options: local, beads, github (comma-separated for multiple)
TASK_SOURCES="local"
GITHUB_TASK_LABEL="ralph-task"
BEADS_FILTER="status:open"

# Circuit breaker thresholds
CB_NO_PROGRESS_THRESHOLD=3
CB_SAME_ERROR_THRESHOLD=5
CB_OUTPUT_DECLINE_THRESHOLD=70
RALPHRCEOF
fi

# Initialize git
git init
echo "# $PROJECT_NAME" > README.md
Expand Down
54 changes: 54 additions & 0 deletions tests/integration/test_project_setup.bats
Original file line number Diff line number Diff line change
Expand Up @@ -489,3 +489,57 @@ teardown() {
# The script properly quotes variables, so spaces should be handled correctly
[[ $status -eq 0 ]]
}

# =============================================================================
# Test: .ralphrc Generation (Issue #136)
# =============================================================================

@test "setup.sh creates .ralphrc file" {
run bash "$SETUP_SCRIPT" test-project

assert_success
assert_file_exists "test-project/.ralphrc"
}

@test "setup.sh .ralphrc contains ALLOWED_TOOLS with Edit" {
bash "$SETUP_SCRIPT" test-project

# .ralphrc should include Edit tool
grep -q "Edit" test-project/.ralphrc
}

@test "setup.sh .ralphrc contains ALLOWED_TOOLS with test execution capabilities" {
bash "$SETUP_SCRIPT" test-project

# .ralphrc should include Bash(npm *) or Bash(pytest) for test execution
grep -qE 'Bash\(npm \*\)|Bash\(pytest\)' test-project/.ralphrc
}

@test "setup.sh .ralphrc ALLOWED_TOOLS matches ralph-enable defaults" {
bash "$SETUP_SCRIPT" test-project

# The expected ALLOWED_TOOLS value that ralph-enable uses
local expected_tools='ALLOWED_TOOLS="Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)"'

# Check that .ralphrc contains the expected ALLOWED_TOOLS line
# Use grep -F for literal string matching (avoids regex interpretation of *)
grep -qF "$expected_tools" test-project/.ralphrc
}

@test "setup.sh .ralphrc is committed in initial git commit" {
bash "$SETUP_SCRIPT" test-project

cd test-project
# Verify .ralphrc is tracked by git (not in untracked files)
run command git ls-files .ralphrc

assert_success
assert_equal "$output" ".ralphrc"
}

@test "setup.sh .ralphrc contains project name" {
bash "$SETUP_SCRIPT" my-custom-project

# .ralphrc should reference the project name
grep -q "my-custom-project" my-custom-project/.ralphrc
}
18 changes: 18 additions & 0 deletions tests/unit/test_cli_modern.bats
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,24 @@ teardown() {
[[ "$output" == *"Read"* ]]
}

@test "CLAUDE_ALLOWED_TOOLS default includes Edit tool (issue #136)" {
# Verify the default includes Edit for file editing
run grep 'CLAUDE_ALLOWED_TOOLS=.*:-' "${BATS_TEST_DIRNAME}/../../ralph_loop.sh"

# The default should include Edit
[[ "$output" == *"Edit"* ]]
}

@test "CLAUDE_ALLOWED_TOOLS default includes test execution tools (issue #136)" {
# Verify the default includes test execution capabilities
run grep 'CLAUDE_ALLOWED_TOOLS=.*:-' "${BATS_TEST_DIRNAME}/../../ralph_loop.sh"

# Should include Bash(npm *) for npm test
[[ "$output" == *'Bash(npm *)'* ]]
# Should include Bash(pytest) for Python tests
[[ "$output" == *'Bash(pytest)'* ]]
}

@test "CLAUDE_USE_CONTINUE defaults to true" {
# Verify by checking the default in ralph_loop.sh via grep
run grep 'CLAUDE_USE_CONTINUE=' "${BATS_TEST_DIRNAME}/../../ralph_loop.sh"
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test_cli_parsing.bats
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ build_ralph_cmd_for_test() {
local CLAUDE_OUTPUT_FORMAT="${3:-json}"
local VERBOSE_PROGRESS="${4:-false}"
local CLAUDE_TIMEOUT_MINUTES="${5:-15}"
local CLAUDE_ALLOWED_TOOLS="${6:-Write,Bash(git *),Read}"
local CLAUDE_ALLOWED_TOOLS="${6:-Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)}"
local CLAUDE_USE_CONTINUE="${7:-true}"
local CLAUDE_SESSION_EXPIRY_HOURS="${8:-24}"
local RALPH_DIR=".ralph"
Expand All @@ -403,7 +403,7 @@ build_ralph_cmd_for_test() {
ralph_cmd="$ralph_cmd --timeout $CLAUDE_TIMEOUT_MINUTES"
fi
# Forward --allowed-tools if non-default
if [[ "$CLAUDE_ALLOWED_TOOLS" != "Write,Bash(git *),Read" ]]; then
if [[ "$CLAUDE_ALLOWED_TOOLS" != "Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)" ]]; then
ralph_cmd="$ralph_cmd --allowed-tools '$CLAUDE_ALLOWED_TOOLS'"
fi
# Forward --no-continue if session continuity disabled
Expand Down Expand Up @@ -460,7 +460,7 @@ build_ralph_cmd_for_test() {
}

@test "monitor does not forward default parameters" {
local result=$(build_ralph_cmd_for_test 100 ".ralph/PROMPT.md" "json" "false" "15" "Write,Bash(git *),Read" "true" "24")
local result=$(build_ralph_cmd_for_test 100 ".ralph/PROMPT.md" "json" "false" "15" "Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)" "true" "24")
# Should only be "ralph" with no extra flags
[[ "$result" == "ralph" ]]
}
Loading