diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..d3d91ccc --- /dev/null +++ b/.dockerignore @@ -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 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..4c21da34 --- /dev/null +++ b/.gitattributes @@ -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 diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 00000000..f0a39256 --- /dev/null +++ b/.github/workflows/docker.yml @@ -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 + + - 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' diff --git a/.gitignore b/.gitignore index 4bd2ecf3..19573e84 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,9 @@ target/ *.swp *.swo +# Docker +docker/tmp/ + # Claude Code local settings .claude/settings.local.json diff --git a/CLAUDE.md b/CLAUDE.md index 36c04ae6..244e51dc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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: @@ -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 diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..54e16f86 --- /dev/null +++ b/Dockerfile @@ -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/* + +# 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"] diff --git a/README.md b/README.md index 0179d141..d4e3eb64 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..c279f236 --- /dev/null +++ b/docker-compose.yml @@ -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"] diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh new file mode 100644 index 00000000..5221c909 --- /dev/null +++ b/docker/docker-entrypoint.sh @@ -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 "$@" diff --git a/docker/ralph-docker b/docker/ralph-docker new file mode 100755 index 00000000..d7a3dd89 --- /dev/null +++ b/docker/ralph-docker @@ -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 "$@" diff --git a/docker/ralph-docker.ps1 b/docker/ralph-docker.ps1 new file mode 100644 index 00000000..3d01f116 --- /dev/null +++ b/docker/ralph-docker.ps1 @@ -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 diff --git a/docs/user-guide/04-docker-setup.md b/docs/user-guide/04-docker-setup.md new file mode 100644 index 00000000..5232bbfd --- /dev/null +++ b/docs/user-guide/04-docker-setup.md @@ -0,0 +1,194 @@ +# Docker Setup (Windows & Cross-Platform) + +Ralph runs natively on Linux and macOS. For **Windows** users (or anyone who prefers containerized execution), Ralph can run inside a Docker container with full functionality. + +## Prerequisites + +- [Docker Desktop](https://www.docker.com/products/docker-desktop/) (Windows/macOS) or Docker Engine (Linux) +- Windows users: Docker Desktop must use the **WSL 2 backend** (default on modern installations) +- **Docker Desktop must be running** before executing any `docker` commands. Look for the Docker whale icon in your system tray (Windows) or menu bar (macOS). +- Your `ANTHROPIC_API_KEY` + +## Quick Start + +### 1. Build the image + +From the Ralph repository root: + +```bash +docker build -t ralph-claude-code . +``` + +### 2. Run Ralph in your project + +```bash +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 +cd C:\path\to\your-project + +docker run -it --rm ` + -e ANTHROPIC_API_KEY="$env:ANTHROPIC_API_KEY" ` + -v "${PWD}:/workspace" ` + ralph-claude-code ` + ralph --monitor +``` + +## Using Docker Compose + +The repository includes a `docker-compose.yml` for convenience: + +```bash +# Set your API key +export ANTHROPIC_API_KEY="sk-ant-..." + +# Run Ralph +docker compose run --rm ralph ralph --monitor +``` + +To customize, edit `docker-compose.yml`. Uncomment the volume mounts for git config and SSH keys if you need git push from inside the container: + +```yaml +volumes: + - ./:/workspace + - ~/.gitconfig:/home/ralph/.gitconfig:ro + - ~/.ssh:/home/ralph/.ssh:ro +``` + +## Convenience Wrapper Scripts + +The `docker/` directory contains wrapper scripts that handle volume mounts, UID mapping, and API key forwarding automatically: + +**Linux/macOS/WSL:** +```bash +./docker/ralph-docker --monitor +./docker/ralph-docker --live --verbose +``` + +**Windows PowerShell:** +```powershell +.\docker\ralph-docker.ps1 --monitor +.\docker\ralph-docker.ps1 --live --verbose +``` + +## File Permissions (UID/GID Mapping) + +When Docker mounts your project directory, files created inside the container need to have the correct ownership on the host. The container supports `RALPH_UID` and `RALPH_GID` environment variables: + +```bash +docker run -it --rm \ + -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \ + -e RALPH_UID="$(id -u)" \ + -e RALPH_GID="$(id -g)" \ + -v "$(pwd):/workspace" \ + ralph-claude-code \ + ralph --monitor +``` + +The wrapper scripts (`docker/ralph-docker`) set these automatically. + +## Git Integration + +To enable git commits and pushes from inside the container, mount your git configuration: + +```bash +docker run -it --rm \ + -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \ + -v "$(pwd):/workspace" \ + -v "$HOME/.gitconfig:/home/ralph/.gitconfig:ro" \ + -v "$HOME/.ssh:/home/ralph/.ssh:ro" \ + ralph-claude-code \ + ralph --monitor +``` + +## Running Tests Inside Docker + +```bash +# Run all tests +docker run --rm ralph-claude-code bash -c 'cd /opt/ralph-claude-code && npm test' + +# Run specific test suite +docker run --rm ralph-claude-code bash -c 'cd /opt/ralph-claude-code && npm run test:unit' +``` + +## Windows-Specific Notes + +### Line Endings + +The repository includes a `.gitattributes` file that forces LF line endings for all shell scripts. This prevents Windows' CRLF line endings from corrupting bash scripts. If you clone the repository on Windows, this is handled automatically. + +If you encounter `\r` errors when running scripts, ensure `.gitattributes` is respected: + +```bash +git config core.autocrlf input +git rm --cached -r . +git reset --hard +``` + +### Volume Mount Performance + +For best performance on Windows, store your projects in the WSL 2 filesystem rather than the Windows filesystem: + +``` +# Faster (WSL filesystem) +\\wsl$\Ubuntu\home\user\my-project + +# Slower (Windows filesystem mounted in WSL) +/mnt/c/Users/user/my-project +``` + +### PowerShell Environment Variables + +```powershell +# Set API key for current session +$env:ANTHROPIC_API_KEY = "sk-ant-..." + +# Or persist across sessions +[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-ant-...", "User") +``` + +## Troubleshooting + +### "error during connect: docker daemon is not running" + +Docker Desktop is not started. On Windows, launch Docker Desktop from the Start menu and wait until the whale icon in the system tray shows "Docker Desktop is running". On macOS, launch it from Applications. On Linux, start the daemon with `sudo systemctl start docker`. + +### "ANTHROPIC_API_KEY is not set" + +The container warns if no API key is provided. Pass it with `-e ANTHROPIC_API_KEY=...`. + +### Permission denied on mounted files + +Set `RALPH_UID` and `RALPH_GID` to match your host user (see File Permissions section above). + +### tmux not working + +Ensure you run the container with `-it` flags (interactive + TTY). Without TTY, tmux cannot create sessions. Use `ralph` without `--monitor` in non-interactive environments. + +### Container can't access the network + +Docker Desktop may need network access enabled. Check Docker Desktop settings and firewall rules. + +## What's in the Container + +The Docker image includes all Ralph dependencies: + +| Component | Version | +|-----------|---------| +| Debian | bookworm-slim | +| Bash | 5.2+ | +| Node.js | 20 LTS | +| jq | Latest | +| Git | Latest | +| tmux | Latest | +| GNU coreutils | Latest | +| Claude Code CLI | Latest | diff --git a/docs/user-guide/README.md b/docs/user-guide/README.md index 86354e92..fb62fef9 100644 --- a/docs/user-guide/README.md +++ b/docs/user-guide/README.md @@ -13,6 +13,9 @@ Learn which files Ralph creates, which ones you should customize, and how they w ### [Writing Effective Requirements](03-writing-requirements.md) Best practices for writing PROMPT.md, when to use specs/, and how fix_plan.md evolves during development. Includes good and bad examples. +### [Docker Setup (Windows & Cross-Platform)](04-docker-setup.md) +Run Ralph inside a Docker container on Windows, Linux, or macOS. Includes Docker Compose setup, file permissions, git integration, and troubleshooting. + ## Example Projects Check out the [examples/](../../examples/) directory for complete, realistic project configurations: