Skip to content
Closed
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
34 changes: 34 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Git
.git

# Node modules
node_modules/

# Ralph state files (rebuilt at runtime)
.ralph/.call_count
.ralph/.last_reset
.ralph/.exit_signals
.ralph/.response_analysis
.ralph/.circuit_breaker_state
.ralph/.circuit_breaker_history
.ralph/.json_parse_result
.ralph/.last_output_length
.ralph/.ralph_session
.ralph/.ralph_session_history
.ralph/.claude_session_id
.ralph/status.json
.ralph/logs/

# Coverage and test artifacts
coverage/
*.log

# OS files
.DS_Store
Thumbs.db

# IDE files
.vscode/
.idea/
*.swp
*.swo
21 changes: 21 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Force LF line endings for all shell scripts and test files
# Prevents Windows CRLF corruption of bash scripts
*.sh text eol=lf
*.bats text eol=lf
*.bash text eol=lf

# Docker files
Dockerfile text eol=lf
docker-compose.yml text eol=lf
docker-entrypoint.sh text eol=lf

# Keep markdown and other text files as auto
*.md text
*.yml text
*.yaml text
*.json text

# Binary files
*.png binary
*.jpg binary
*.gif binary
51 changes: 51 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Docker Build

on:
push:
branches: [ main, develop ]
paths:
- 'Dockerfile'
- 'docker/**'
- '.dockerignore'
- 'install.sh'
- 'lib/**'
- 'ralph_loop.sh'
pull_request:
branches: [ main ]
paths:
- 'Dockerfile'
- 'docker/**'
- '.dockerignore'
- 'install.sh'
- 'lib/**'
- 'ralph_loop.sh'

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Update actions/checkout from v3 to v4.

As flagged by actionlint, actions/checkout@v3 uses Node.js 16 which is deprecated on GitHub Actions. Update to v4.

-    - uses: actions/checkout@v3
+    - uses: actions/checkout@v4
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: actions/checkout@v3
- uses: actions/checkout@v4
🧰 Tools
🪛 actionlint (1.7.10)

[error] 28-28: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In @.github/workflows/docker.yml at line 28, Update the GitHub Actions checkout
step by replacing the uses reference "actions/checkout@v3" with
"actions/checkout@v4" to pick up Node.js 18+ compatibility; locate the workflow
step that contains the literal uses: actions/checkout@v3 and change it to
actions/checkout@v4, then run a quick actionlint or dry run to verify no other
compatibility changes are required.


- name: Build Docker image
run: docker build -t ralph-claude-code:test .

- name: Verify Ralph is installed
run: docker run --rm ralph-claude-code:test ralph --help

- name: Verify dependencies
run: |
docker run --rm ralph-claude-code:test bash -c '
echo "=== Checking dependencies ==="
bash --version | head -1
node --version
npm --version
jq --version
git --version
tmux -V
timeout --version | head -1
echo "=== All dependencies OK ==="
'

- name: Run tests inside Docker
run: docker run --rm ralph-claude-code:test bash -c 'cd /opt/ralph-claude-code && npm test'
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ target/
*.swp
*.swo

# Docker
docker/tmp/

# Claude Code local settings
.claude/settings.local.json

Expand Down
29 changes: 29 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,34 @@ After installation, the following global commands are available:
- `ralph-enable` - Interactive wizard to enable Ralph in existing projects
- `ralph-enable-ci` - Non-interactive version for CI/automation

## Docker Support

Ralph can run inside a Docker container for Windows users or containerized workflows.

### Docker Files
- **`Dockerfile`** - Debian slim image with all Ralph dependencies (bash, jq, git, tmux, Node.js 20, Claude Code CLI)
- **`docker-compose.yml`** - Compose configuration with volume mounts and API key passthrough
- **`docker/docker-entrypoint.sh`** - Entrypoint handling UID/GID remapping and git safe.directory
- **`docker/ralph-docker`** - Bash convenience wrapper for `docker run`
- **`docker/ralph-docker.ps1`** - PowerShell convenience wrapper for Windows
- **`.dockerignore`** - Build context exclusions
- **`.gitattributes`** - Forces LF line endings for shell scripts (prevents Windows CRLF corruption)

### Docker Commands
```bash
# Build image
docker build -t ralph-claude-code .

# Run Ralph
docker run -it --rm -e ANTHROPIC_API_KEY="$KEY" -v "$(pwd):/workspace" ralph-claude-code ralph --monitor

# Run tests inside container
docker run --rm ralph-claude-code bash -c 'cd /opt/ralph-claude-code && npm test'
```

### CI Workflow
`.github/workflows/docker.yml` verifies the Docker image builds and all tests pass inside the container.

## Integration Points

Ralph integrates with:
Expand All @@ -338,6 +366,7 @@ Ralph integrates with:
- **Git**: Expects projects to be git repositories
- **jq**: For JSON processing of status and exit signals
- **GitHub Actions**: CI/CD pipeline for automated testing
- **Docker**: Container-based execution for Windows and cross-platform support
- **Standard Unix tools**: bash, grep, date, etc.

## Exit Conditions and Thresholds
Expand Down
46 changes: 46 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
FROM debian:bookworm-slim

# System dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
jq \
git \
tmux \
coreutils \
curl \
ca-certificates \
gosu \
procps \
&& rm -rf /var/lib/apt/lists/*

# Install Node.js 20 LTS
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
Comment on lines +16 to +19
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Node.js 20 end of life date EOL 2026

💡 Result:

Node.js 20.x (Iron) reaches End-of-Life (EOL) on April 30, 2026—after that date, the Node.js project ends official maintenance/security support for the 20.x line. [1][2]


🌐 Web query:

Node.js LTS schedule 22 24 support timeline 2026

💡 Result:

Node.js LTS support timeline (v22 vs v24) in/around 2026

Node.js 22.x (“Jod”)

  • Active LTS started: 2024-10-29
  • Maintenance LTS started: 2025-10-21 (so throughout all of 2026, v22 is in Maintenance LTS)
  • End-of-life (EOL): 2027-04-30 (security fixes stop) [2]
  • Current status shown on the official releases page: Maintenance LTS [1]

Node.js 24.x (“Krypton”)

  • Active LTS started: 2025-10-28 (so throughout most of 2026, v24 is in Active LTS)
  • Maintenance LTS starts: 2026-10-20 (switches from Active → Maintenance during 2026)
  • End-of-life (EOL): 2028-04-30 [2]
  • Current status shown on the official releases page: Active LTS [1]

Practical takeaway for 2026:

  • If you want the “most supported” LTS line during 2026, v24 is the primary choice (Active LTS until Oct 20, 2026).
  • v22 remains supported in 2026, but only in Maintenance LTS (security/backports, reduced feature/bugfix scope) until Apr 30, 2027. [2]

Sources: official Node.js releases page [1] and the Node.js Release Working Group schedule [2].


Upgrade to Node.js 24 LTS instead — Node.js 20 reaches end-of-life April 30, 2026.

Node.js 20 maintenance support ends April 30, 2026. Node.js 22 is currently in Maintenance LTS. For better long-term support, use Node.js 24, which is the current Active LTS and will remain supported through October 2026.

-RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
+RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Install Node.js 20 LTS
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js 20 LTS
RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
🤖 Prompt for AI Agents
In `@Dockerfile` around lines 16 - 19, Update the Node.js setup step in the
Dockerfile to use Node.js 24 LTS instead of 20 by replacing the nodesource setup
script reference "setup_20.x" with "setup_24.x" in the RUN command that installs
Node.js; ensure the rest of the command (apt-get install -y
--no-install-recommends nodejs && rm -rf /var/lib/apt/lists/*) remains unchanged
so the image still installs nodejs and cleans apt lists.


# Install Claude Code CLI globally
RUN npm install -g @anthropic-ai/claude-code

# Create ralph user
RUN groupadd -g 1000 ralph \
&& useradd -m -u 1000 -g ralph -s /bin/bash ralph

# Copy Ralph source
COPY . /opt/ralph-claude-code/

# Install Ralph as the ralph user
USER ralph
RUN cd /opt/ralph-claude-code && bash install.sh
ENV PATH="/home/ralph/.local/bin:${PATH}"

# Switch back to root for entrypoint (handles UID remapping)
USER root

# Copy entrypoint
COPY docker/docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

WORKDIR /workspace

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["ralph", "--help"]
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,36 @@ To completely remove Ralph from your system:
curl -sL https://raw.githubusercontent.com/frankbria/ralph-claude-code/main/uninstall.sh | bash
```

## Docker Setup (Windows & Cross-Platform)

Ralph can run inside a Docker container, which is the recommended approach for **Windows** users. It also works on Linux and macOS.

```bash
# 1. Build the image (one time)
docker build -t ralph-claude-code .

# 2. Run Ralph in your project
cd /path/to/your-project
docker run -it --rm \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
-v "$(pwd):/workspace" \
ralph-claude-code \
ralph --monitor
```

**Windows PowerShell:**
```powershell
docker run -it --rm `
-e ANTHROPIC_API_KEY="$env:ANTHROPIC_API_KEY" `
-v "${PWD}:/workspace" `
ralph-claude-code `
ralph --monitor
```

Convenience wrapper scripts are available in `docker/` (bash and PowerShell).

> See [Docker Setup Guide](docs/user-guide/04-docker-setup.md) for full documentation including Docker Compose, file permissions, git integration, and troubleshooting.

## Understanding Ralph Files

After running `ralph-enable` or `ralph-import`, you'll have a `.ralph/` directory with several files. Here's what each file does and whether you need to edit it:
Expand Down
21 changes: 21 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
services:
ralph:
build:
context: .
dockerfile: Dockerfile
image: ralph-claude-code:latest
container_name: ralph
stdin_open: true
tty: true
working_dir: /workspace
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- RALPH_UID=${RALPH_UID:-1000}
- RALPH_GID=${RALPH_GID:-1000}
volumes:
- ./:/workspace
# Optional: mount git config for commits
# - ~/.gitconfig:/home/ralph/.gitconfig:ro
# Optional: mount SSH keys for git push
# - ~/.ssh:/home/ralph/.ssh:ro
command: ["ralph", "--help"]
26 changes: 26 additions & 0 deletions docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash
set -e

# Default UID/GID matching typical Linux/macOS user
RALPH_UID=${RALPH_UID:-1000}
RALPH_GID=${RALPH_GID:-1000}

# Remap ralph user UID/GID to match host user (avoids file permission issues on bind mounts)
if [ "$(id -u ralph)" != "$RALPH_UID" ] || [ "$(id -g ralph)" != "$RALPH_GID" ]; then
groupmod -g "$RALPH_GID" ralph 2>/dev/null || true
usermod -u "$RALPH_UID" -g "$RALPH_GID" -d /home/ralph ralph 2>/dev/null || true
chown -R ralph:ralph /home/ralph 2>/dev/null || true
fi

# Git safe.directory for mounted workspace
gosu ralph git config --global --add safe.directory /workspace 2>/dev/null || true

# Warn if API key is missing
if [ -z "$ANTHROPIC_API_KEY" ]; then
echo "WARNING: ANTHROPIC_API_KEY is not set. Ralph will not be able to call Claude."
echo "Set it with: docker run -e ANTHROPIC_API_KEY=your-key ..."
echo ""
fi

# Execute command as ralph user
exec gosu ralph "$@"
45 changes: 45 additions & 0 deletions docker/ralph-docker
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/bin/bash
# ralph-docker - Convenience wrapper for running Ralph in Docker
#
# Usage:
# ./docker/ralph-docker [ralph-options]
#
# Examples:
# ./docker/ralph-docker --help
# ./docker/ralph-docker --monitor
# ./docker/ralph-docker --live --verbose
#
# Environment:
# ANTHROPIC_API_KEY Required. Your Anthropic API key.
# RALPH_IMAGE Optional. Docker image name (default: ralph-claude-code:latest)

set -e

IMAGE_NAME="${RALPH_IMAGE:-ralph-claude-code:latest}"

if [ -z "$ANTHROPIC_API_KEY" ]; then
echo "Error: ANTHROPIC_API_KEY environment variable is not set."
echo "Export it first: export ANTHROPIC_API_KEY=sk-ant-..."
exit 1
fi

EXTRA_VOLUMES=()

# Mount git config if available
if [ -f "$HOME/.gitconfig" ]; then
EXTRA_VOLUMES+=(-v "$HOME/.gitconfig:/home/ralph/.gitconfig:ro")
fi

# Mount SSH keys if available
if [ -d "$HOME/.ssh" ]; then
EXTRA_VOLUMES+=(-v "$HOME/.ssh:/home/ralph/.ssh:ro")
fi

docker run -it --rm \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
-e RALPH_UID="$(id -u)" \
-e RALPH_GID="$(id -g)" \
-v "$(pwd):/workspace" \
"${EXTRA_VOLUMES[@]}" \
"$IMAGE_NAME" \
ralph "$@"
40 changes: 40 additions & 0 deletions docker/ralph-docker.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# ralph-docker.ps1 - Convenience wrapper for running Ralph in Docker on Windows
#
# Usage:
# .\docker\ralph-docker.ps1 [ralph-options]
#
# Examples:
# .\docker\ralph-docker.ps1 --help
# .\docker\ralph-docker.ps1 --monitor
# .\docker\ralph-docker.ps1 --live --verbose
#
# Environment:
# ANTHROPIC_API_KEY Required. Your Anthropic API key.
# RALPH_IMAGE Optional. Docker image name (default: ralph-claude-code:latest)

param(
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$RalphArgs
)

$ImageName = if ($env:RALPH_IMAGE) { $env:RALPH_IMAGE } else { "ralph-claude-code:latest" }

if (-not $env:ANTHROPIC_API_KEY) {
Write-Error "ANTHROPIC_API_KEY environment variable is not set."
Write-Host 'Set it first: $env:ANTHROPIC_API_KEY = "sk-ant-..."'
exit 1
}

$DockerArgs = @(
"run", "-it", "--rm",
"-e", "ANTHROPIC_API_KEY=$env:ANTHROPIC_API_KEY",
"-v", "${PWD}:/workspace",
$ImageName,
"ralph"
)

if ($RalphArgs) {
$DockerArgs += $RalphArgs
}

& docker @DockerArgs
Comment on lines +36 to +40
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing exit code propagation from docker run.

If docker run fails, the script exits with PowerShell's default exit code (0) rather than propagating Docker's non-zero exit code. This can mask failures in automation.

Proposed fix
 if ($RalphArgs) {
     $DockerArgs += $RalphArgs
 }
 
 & docker `@DockerArgs`
+$exitCode = $LASTEXITCODE
+if ($exitCode -ne 0) {
+    exit $exitCode
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ($RalphArgs) {
$DockerArgs += $RalphArgs
}
& docker @DockerArgs
if ($RalphArgs) {
$DockerArgs += $RalphArgs
}
& docker `@DockerArgs`
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
exit $exitCode
}
🤖 Prompt for AI Agents
In `@docker/ralph-docker.ps1` around lines 36 - 40, The script currently invokes
Docker with "& docker `@DockerArgs`" but does not propagate Docker's exit code;
after the call capture PowerShell's $LASTEXITCODE (or check $? then use
$LASTEXITCODE) and call exit with that value so non-zero Docker failures are
returned to the caller; update the section around the $RalphArgs/$DockerArgs
handling and the "& docker `@DockerArgs`" invocation to record $LASTEXITCODE and
exit $LASTEXITCODE when non-zero.

Loading
Loading