feat(loop): validate Claude Code CLI command at startup (#97)#191
feat(loop): validate Claude Code CLI command at startup (#97)#191
Conversation
- Add validate_claude_command() to check CLI exists before loop starts - Make CLAUDE_CODE_CMD configurable via .ralphrc (auto-detected during setup) - Add early process failure detection in background mode (sleep+kill -0) - Update generate_ralphrc() and setup.sh to include CLAUDE_CODE_CMD - Update ralph_import.sh to respect .ralphrc for CLAUDE_CODE_CMD - Add 10 new tests for command validation and .ralphrc loading (556→566) - Update documentation with troubleshooting and configuration Closes #97
WalkthroughThe pull request adds Claude Code CLI command detection, validation, and configuration across the codebase. It introduces a Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant RalphLoop as ralph_loop.sh
participant Validation as validate_claude_command()
participant Config as .ralphrc<br/>(CLAUDE_CODE_CMD)
participant CLI as Claude CLI<br/>(claude/npx)
User->>RalphLoop: Start ralph loop
RalphLoop->>RalphLoop: Load environment & config
RalphLoop->>Validation: Call validate_claude_command()
Validation->>Config: Check CLAUDE_CODE_CMD value
Config-->>Validation: Return configured command
Validation->>CLI: Test command availability
alt Command Found
CLI-->>Validation: Success
Validation-->>RalphLoop: Validation passed
RalphLoop->>CLI: Execute Claude Code
CLI-->>RalphLoop: Process result
RalphLoop->>User: Continue loop
else Command Not Found
CLI-->>Validation: Not found
Validation->>User: Error message +<br/>installation guidance
User-->>RalphLoop: Exit with remediation
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Comment |
Validate and fail fast on the Claude Code CLI command at startup in
|
Code Review: feat(loop): validate Claude Code CLI command at startup (#97)This PR adds pre-flight validation of the Claude Code CLI command to prevent silent hangs. The implementation is well-structured and follows existing patterns, but there are a few areas for improvement. ✅ Strengths
|
|
PR review posted successfully. The key findings are: Summary:
Recommendation: Approve with changes - Fix the grep parsing bug before merging. The color variable ordering is less critical but worth addressing. |
PR 191 Review: feat(loop): validate Claude Code CLI command at startupThis is a solid, well-scoped implementation of the CLI validation requirement from issue 97. The approach is sensible and the error messaging is user-friendly. A few issues worth addressing: Bug: Changelog entry misrepresents test count deltaIn to: This is contradictory: "8 new tests" but a delta of 18 (548→566). The historical record for v0.11.5 should stay as Issue:
|
| if ! kill -0 $claude_pid 2>/dev/null; then | ||
| wait $claude_pid 2>/dev/null | ||
| local early_exit=$? |
There was a problem hiding this comment.
🟡 Medium
ralph_loop.sh:1322 Early failure detection treats exit code 0 as a failure. Consider checking $early_exit -ne 0 before entering the error path.
- if ! kill -0 $claude_pid 2>/dev/null; then
- wait $claude_pid 2>/dev/null
- local early_exit=$?
+ if ! kill -0 $claude_pid 2>/dev/null; then
+ wait $claude_pid 2>/dev/null
+ local early_exit=$?
+ # Only treat non-zero exit as failure (Issue #97)
+ if [[ $early_exit -eq 0 ]]; then
+ log_status "INFO" "Claude Code completed quickly (exit code 0)"
+ else🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file ralph_loop.sh around lines 1322-1324:
Early failure detection treats exit code 0 as a failure. Consider checking `$early_exit -ne 0` before entering the error path.
| [[ -n "$_env_VERBOSE_PROGRESS" ]] && VERBOSE_PROGRESS="$_env_VERBOSE_PROGRESS" | ||
| [[ -n "$_env_CB_COOLDOWN_MINUTES" ]] && CB_COOLDOWN_MINUTES="$_env_CB_COOLDOWN_MINUTES" | ||
| [[ -n "$_env_CB_AUTO_RESET" ]] && CB_AUTO_RESET="$_env_CB_AUTO_RESET" | ||
| [[ -n "$_env_CLAUDE_CODE_CMD" ]] && CLAUDE_CODE_CMD="$_env_CLAUDE_CODE_CMD" |
There was a problem hiding this comment.
🟡 Medium
ralph_loop.sh:157 The environment override for CLAUDE_CODE_CMD won't work because _env_CLAUDE_CODE_CMD is captured (line 48) after the default is set (line 29). Consider changing line 29 to CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-claude}" to preserve user values.
🚀 Want me to fix this? Reply ex: "fix it for me".
🤖 Prompt for AI
In file ralph_loop.sh around line 157:
The environment override for `CLAUDE_CODE_CMD` won't work because `_env_CLAUDE_CODE_CMD` is captured (line 48) after the default is set (line 29). Consider changing line 29 to `CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-claude}"` to preserve user values.
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ralph_loop.sh (1)
37-48:⚠️ Potential issue | 🟠 MajorCLAUDE_CODE_CMD overrides are being overwritten before load_ralphrc.
CLAUDE_CODE_CMDis set to"claude"before_env_CLAUDE_CODE_CMDis captured, so_env_CLAUDE_CODE_CMDis always non-empty and load_ralphrc will always restore"claude", ignoring.ralphrc/environment overrides. Capture env first and set the default after.Suggested fix
-CLAUDE_CODE_CMD="claude" +CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-}" ... -_env_CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-}" +_env_CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-}" -# Now set defaults (only if not already set by environment) +# Now set defaults (only if not already set by environment) +CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-claude}"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ralph_loop.sh` around lines 37 - 48, The issue is that CLAUDE_CODE_CMD is being defaulted to "claude" before you save the original environment into _env_CLAUDE_CODE_CMD, so load_ralphrc will always restore the default and ignore .ralphrc or external env values; fix by first capturing the raw environment into _env_CLAUDE_CODE_CMD (use _env_CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-}") along with the other _env_* variables, then set the default CLAUDE_CODE_CMD="claude" afterward so load_ralphrc can correctly detect and restore user-provided values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@CLAUDE.md`:
- Around line 219-232: There are inconsistent package-name references for the
Claude Code CLI: replace every occurrence of the incorrect
"@anthropic/claude-code" with the canonical "@anthropic-ai/claude-code" in the
docs and scripts; specifically update the misplaced reference in CLAUDE.md (the
other section that currently shows "@anthropic/claude-code") and the install
line in create_files.sh so they match the CLAUDE_CODE_CMD documentation and
validation (validate_claude_command()) to avoid install/runtime confusion.
In `@lib/enable_core.sh`:
- Around line 684-690: Change the snake_case variable claude_cmd to camelCase
claudeCmd and update all references; also correct the npx fallback package name
from "@anthropic-ai/claude-code" to "anthropic/claude-code" so the fallback
becomes "npx anthropic/claude-code"; ensure the command -v checks and the
assignment inside the auto-detect block use claudeCmd consistently (including
any later uses of the variable).
In `@ralph_import.sh`:
- Around line 9-13: The code reads CLAUDE_CODE_CMD from .ralphrc into a
snake_case _ralphrc_cmd and later calls command -v on the entire string which
fails for npx-style values; rename the temp variable to camelCase (e.g.,
ralphRcCmd) and extract/validate only the executable token (the first
whitespace-delimited word) before assigning to CLAUDE_CODE_CMD or before calling
command -v; reuse or call the existing validate_claude_command-style logic (or
implement equivalent) to check the executable token and preserve the full
original value in CLAUDE_CODE_CMD when valid.
In `@ralph_loop.sh`:
- Around line 1319-1346: The early-failure block currently treats any immediate
exit (within sleep 1) as an error; change it to only treat non-zero early exits
as failures: after wait $claude_pid capture the exit into earlyExit (camelCase)
and read earlyOutput (camelCase) from "$output_file"; if earlyExit is non-zero
then log via log_status and print the diagnostic messages referencing
CLAUDE_CODE_CMD as now, otherwise treat a zero earlyExit as a normal success
(skip error logging and return/continue accordingly). Also rename variables
early_exit -> earlyExit and early_output -> earlyOutput throughout this block to
follow camelCase shell style.
In `@README.md`:
- Around line 21-22: Update the README test-summary and any test-count
badges/text so all references reflect 566 tests and a +18 delta instead of the
old 556/556 and “Added 8 new tests”; specifically find the "Test Coverage"
badge/header and the lines that say "556/556 passing" and "Added 8 new tests"
(occurrences noted around the sections referenced in the review) and change them
to consistent wording (e.g., "566 tests, 100% pass" and "Added 18 new tests" or
equivalent delta language) so every summary, badge and sentence that mentions
test counts or deltas is synchronized.
---
Outside diff comments:
In `@ralph_loop.sh`:
- Around line 37-48: The issue is that CLAUDE_CODE_CMD is being defaulted to
"claude" before you save the original environment into _env_CLAUDE_CODE_CMD, so
load_ralphrc will always restore the default and ignore .ralphrc or external env
values; fix by first capturing the raw environment into _env_CLAUDE_CODE_CMD
(use _env_CLAUDE_CODE_CMD="${CLAUDE_CODE_CMD:-}") along with the other _env_*
variables, then set the default CLAUDE_CODE_CMD="claude" afterward so
load_ralphrc can correctly detect and restore user-provided values.
| CLAUDE_CODE_CMD="claude" # Claude Code CLI command (configurable via .ralphrc, Issue #97) | ||
| CLAUDE_OUTPUT_FORMAT="json" # Output format: json (default) or text | ||
| CLAUDE_ALLOWED_TOOLS="Write,Read,Edit,Bash(git add *),Bash(git commit *),...,Bash(npm *),Bash(pytest)" # Allowed tool permissions (see File Protection) | ||
| CLAUDE_USE_CONTINUE=true # Enable session continuity | ||
| CLAUDE_MIN_VERSION="2.0.76" # Minimum Claude CLI version | ||
| ``` | ||
|
|
||
| **Claude Code CLI Command (Issue #97):** | ||
| - `CLAUDE_CODE_CMD` defaults to `"claude"` (global install) | ||
| - Configurable via `.ralphrc` for alternative installations (e.g., `"npx @anthropic-ai/claude-code"`) | ||
| - Auto-detected during `ralph-enable` and `ralph-setup` (prefers `claude` if available, falls back to npx) | ||
| - Validated at startup with `validate_claude_command()` — displays clear error with installation instructions if not found | ||
| - Environment variable `CLAUDE_CODE_CMD` takes precedence over `.ralphrc` | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Search for all references to anthropic/claude-code in the codebase
rg "anthropic.*claude-code|claude-code.*anthropic" -iRepository: frankbria/ralph-claude-code
Length of output: 2497
🏁 Script executed:
# Also search for references in .ralphrc examples and setup documentation
rg -t md -t sh "CLAUDE_CODE_CMD|npx" | head -30Repository: frankbria/ralph-claude-code
Length of output: 2775
🌐 Web query:
Claude Code CLI npm package name official documentation
💡 Result:
- Official Claude Code CLI npm package name:
@anthropic-ai/claude-code(installed e.g.npm install -g@anthropic-ai/claude-code``). [1][2] - Official documentation: Anthropic’s “Claude Code SDK” docs (includes CLI usage via the
claudecommand). [1]
Sources: [1] Anthropic docs, Claude Code SDK; [2] npm package page for @anthropic-ai/claude-code.
Fix inconsistent Claude Code CLI package name references across the codebase.
The canonical npm package is @anthropic-ai/claude-code, but inconsistencies exist:
- Lines 219-232 in CLAUDE.md are correct (
@anthropic-ai/claude-code) - However, another section of CLAUDE.md incorrectly references
@anthropic/claude-code(missing-ai) create_files.shalso incorrectly uses@anthropic/claude-code
Update these references to @anthropic-ai/claude-code for consistency across setup documentation and scripts to avoid user confusion during installation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@CLAUDE.md` around lines 219 - 232, There are inconsistent package-name
references for the Claude Code CLI: replace every occurrence of the incorrect
"@anthropic/claude-code" with the canonical "@anthropic-ai/claude-code" in the
docs and scripts; specifically update the misplaced reference in CLAUDE.md (the
other section that currently shows "@anthropic/claude-code") and the install
line in create_files.sh so they match the CLAUDE_CODE_CMD documentation and
validation (validate_claude_command()) to avoid install/runtime confusion.
| # Auto-detect Claude Code CLI command | ||
| local claude_cmd="claude" | ||
| if ! command -v claude &>/dev/null; then | ||
| if command -v npx &>/dev/null; then | ||
| claude_cmd="npx @anthropic-ai/claude-code" | ||
| fi | ||
| fi |
There was a problem hiding this comment.
Verify the Claude Code CLI package name used for the npx fallback.
The fallback uses npx @anthropic-ai/claude-code``. The repo integration guidance calls out npx anthropic/claude-code; if the package name is wrong, new .ralphrc defaults will be unusable. Also, `claude_cmd` is snake_case; please switch to camelCase (e.g., `claudeCmd`) to match shell style rules.
What is the correct npm package name and npx invocation for the Claude Code CLI? Is it `@anthropic-ai/claude-code` or `@anthropic/claude-code`?
Based on learnings: All integration points must be with: Claude Code CLI (npx anthropic/claude-code), tmux terminal multiplexer, Git repositories, jq for JSON processing, GitHub Actions CI/CD, and standard Unix tools (bash, grep, date, etc.).
As per coding guidelines: **/*.sh: Use camelCase for variable names in bash and shell scripts.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/enable_core.sh` around lines 684 - 690, Change the snake_case variable
claude_cmd to camelCase claudeCmd and update all references; also correct the
npx fallback package name from "@anthropic-ai/claude-code" to
"anthropic/claude-code" so the fallback becomes "npx anthropic/claude-code";
ensure the command -v checks and the assignment inside the auto-detect block use
claudeCmd consistently (including any later uses of the variable).
| # Load CLAUDE_CODE_CMD from .ralphrc if available | ||
| if [[ -f ".ralphrc" ]]; then | ||
| _ralphrc_cmd=$(grep "^CLAUDE_CODE_CMD=" ".ralphrc" 2>/dev/null | cut -d= -f2- | tr -d '"' | tr -d "'") | ||
| [[ -n "$_ralphrc_cmd" ]] && CLAUDE_CODE_CMD="$_ralphrc_cmd" | ||
| fi |
There was a problem hiding this comment.
Handle npx-style CLAUDE_CODE_CMD in dependency checks + camelCase naming.
Loading CLAUDE_CODE_CMD enables values like npx …, but the later command -v "$CLAUDE_CODE_CMD" will always warn when the value contains spaces. Consider validating only the executable token (or reuse a validate_claude_command-style check). Also, _ralphrc_cmd should be camelCase.
Suggested fix for the dependency check
- if ! command -v "$CLAUDE_CODE_CMD" &> /dev/null 2>&1; then
+ local claudeCmdBin="${CLAUDE_CODE_CMD%% *}"
+ if ! command -v "$claudeCmdBin" &> /dev/null 2>&1; then🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ralph_import.sh` around lines 9 - 13, The code reads CLAUDE_CODE_CMD from
.ralphrc into a snake_case _ralphrc_cmd and later calls command -v on the entire
string which fails for npx-style values; rename the temp variable to camelCase
(e.g., ralphRcCmd) and extract/validate only the executable token (the first
whitespace-delimited word) before assigning to CLAUDE_CODE_CMD or before calling
command -v; reuse or call the existing validate_claude_command-style logic (or
implement equivalent) to check the executable token and preserve the full
original value in CLAUDE_CODE_CMD when valid.
| # Early failure detection: if the command doesn't exist or fails immediately, | ||
| # the backgrounded process dies before the monitoring loop starts (Issue #97) | ||
| sleep 1 | ||
| if ! kill -0 $claude_pid 2>/dev/null; then | ||
| wait $claude_pid 2>/dev/null | ||
| local early_exit=$? | ||
| local early_output="" | ||
| if [[ -f "$output_file" && -s "$output_file" ]]; then | ||
| early_output=$(tail -5 "$output_file" 2>/dev/null) | ||
| fi | ||
| log_status "ERROR" "❌ Claude Code process exited immediately (exit code: $early_exit)" | ||
| if [[ -n "$early_output" ]]; then | ||
| log_status "ERROR" "Output: $early_output" | ||
| fi | ||
| echo "" | ||
| echo -e "${RED}Claude Code failed to start.${NC}" | ||
| echo "" | ||
| echo -e "${YELLOW}Possible causes:${NC}" | ||
| echo " - '${CLAUDE_CODE_CMD}' command not found or not executable" | ||
| echo " - Claude Code CLI not installed" | ||
| echo " - Authentication or configuration issue" | ||
| echo "" | ||
| echo -e "${YELLOW}To fix:${NC}" | ||
| echo " 1. Verify Claude Code works: ${CLAUDE_CODE_CMD} --version" | ||
| echo " 2. Or set a different command in .ralphrc: CLAUDE_CODE_CMD=\"npx @anthropic-ai/claude-code\"" | ||
| echo "" | ||
| return 1 | ||
| fi |
There was a problem hiding this comment.
Early-failure check can misclassify fast successes.
If the CLI exits within 1s with exit code 0, this block still logs an error and returns 1. Consider only treating non‑zero early exits as failures or short‑circuit to the normal success path. Also, early_exit / early_output should be camelCase per shell style.
As per coding guidelines: **/*.sh: Use camelCase for variable names in bash and shell scripts.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ralph_loop.sh` around lines 1319 - 1346, The early-failure block currently
treats any immediate exit (within sleep 1) as an error; change it to only treat
non-zero early exits as failures: after wait $claude_pid capture the exit into
earlyExit (camelCase) and read earlyOutput (camelCase) from "$output_file"; if
earlyExit is non-zero then log via log_status and print the diagnostic messages
referencing CLAUDE_CODE_CMD as now, otherwise treat a zero earlyExit as a normal
success (skip error logging and return/continue accordingly). Also rename
variables early_exit -> earlyExit and early_output -> earlyOutput throughout
this block to follow camelCase shell style.
| **Test Coverage**: 566 tests, 100% pass rate | ||
|
|
There was a problem hiding this comment.
Align test-count references after the 566 update.
Several lines now say 566 tests, but other nearby lines still show 556/556 passing and “Added 8 new tests” even though 548 → 566 implies +18. Please update the badge/summary text so counts and deltas match.
Based on learnings: Documentation MUST remain synchronized with codebase: inline script comments for all functions, README updates for features, template file updates for patterns, and CLAUDE.md updates for new commands and behaviors.
Also applies to: 50-51, 639-640, 665-667, 773-773
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@README.md` around lines 21 - 22, Update the README test-summary and any
test-count badges/text so all references reflect 566 tests and a +18 delta
instead of the old 556/556 and “Added 8 new tests”; specifically find the "Test
Coverage" badge/header and the lines that say "556/556 passing" and "Added 8 new
tests" (occurrences noted around the sections referenced in the review) and
change them to consistent wording (e.g., "566 tests, 100% pass" and "Added 18
new tests" or equivalent delta language) so every summary, badge and sentence
that mentions test counts or deltas is synchronized.

Summary
Implements #97 — Ralph now validates that the Claude Code CLI is available before starting the loop, instead of hanging or exiting silently.
validate_claude_command(): Pre-flight check that runs inmain()before the loop. Checkscommand -vfor direct commands, validates npx availability for npx-based commandsCLAUDE_CODE_CMD: Now settable via.ralphrc(auto-detected duringralph-enableandralph-setup— prefersclaudeif installed, falls back tonpx @anthropic-ai/claude-code)sleep 1+kill -0check, preventing the silent hang that was the original reportAcceptance Criteria
.ralphrc.ralphrcfiles includeCLAUDE_CODE_CMDwith auto-detected defaultTest Plan
test_cli_modern.bats(556 → 566 total).ralphrcloading and env var precedenceCloses #97
Summary by CodeRabbit
New Features
.ralphrcfile, with fallback to npx for alternative invocation methods.Documentation
Tests