An open API service indexing awesome lists of open source software.

https://github.com/decocms/ralph


https://github.com/decocms/ralph

Last synced: about 1 month ago
JSON representation

Awesome Lists containing this project

README

          

# Ralph - Autonomous Claude Code Runner for GitHub Issues

Ralph is a Kubernetes-native tool that runs Claude Code autonomously to implement solutions for GitHub issues. Pass it a repo, issue number, and branch name — Claude will read the issue context and work until the task is complete.

[![Release](https://github.com/decocms/ralph/actions/workflows/release.yaml/badge.svg)](https://github.com/decocms/ralph/actions/workflows/release.yaml)

## Features

- **GitHub Issue Integration** — Fetches issue title, description, labels, and comments
- **Autonomous Loop** — Runs Claude Code iteratively until completion signal
- **Smart Fork Detection** — Automatically forks repos when no write access, pushes directly when allowed
- **Automatic PR Creation** — Opens pull requests with proper issue references
- **Cost Tracking** — Reports token usage and estimated costs at completion
- **Issue Commenting** — Posts summary with PR link and cost to the original issue
- **Cross-Repo Issues** — Fetch issues from one repo, implement in another
- **Safety Limits** — Max iterations and rate limiting prevent runaway costs
- **Kubernetes Native** — Helm chart for easy deployment
- **SSH Authentication** — Secure Git operations with SSH keys

## Quick Start

### Prerequisites

- Kubernetes cluster with `kubectl` configured
- [Helm](https://helm.sh/docs/intro/install/) installed
- GitHub Personal Access Token
- Anthropic API Key
- SSH key for Git push access

### 1. Install the Helm Chart

```bash
# Add the chart repository (or clone this repo)
git clone https://github.com/decocms/ralph.git
cd ralph
```

### 2. Create Secrets

```bash
# Create namespace
kubectl create namespace ralph

# Create API secrets
kubectl create secret generic ralph-secrets \
--from-literal=github-token='ghp_xxxxxxxxxxxx' \
--from-literal=anthropic-api-key='sk-ant-xxxxxxxxxxxx' \
-n ralph

# Create SSH key secret
kubectl create secret generic ralph-ssh-key \
--from-file=ssh-private-key=$HOME/.ssh/id_rsa \
-n ralph
```

### 3. Run a Job

```bash
# Using the CLI script
NAMESPACE=ralph ./ralph.sh git@github.com:owner/repo.git 42 fix/issue-42

# Or directly with Helm
helm install my-job ./charts/ralph \
--set job.repo="git@github.com:owner/repo.git" \
--set job.issueId="42" \
--set job.branch="fix/issue-42" \
--namespace ralph
```

## Usage

### CLI Script

```bash
./ralph.sh
```

The `` can be:
- A number (e.g., `226`) — fetches from target repo
- A full GitHub URL (e.g., `https://github.com/org/repo/issues/42`) — fetches from that repo

### Examples

```bash
# Issue from same repo
./ralph.sh git@github.com:acme/api.git 42 fix/issue-42

# Issue from different repo (cross-repo)
./ralph.sh git@github.com:acme/api.git https://github.com/acme/tasks/issues/123 fix/task-123
```

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `NAMESPACE` | `default` | Kubernetes namespace |
| `CHART_PATH` | `./charts/ralph` | Path to Helm chart |
| `IMAGE_REPO` | `ghcr.io/decocms/ralph` | Container image |
| `IMAGE_TAG` | `latest` | Image tag |

## Helm Chart

### Installation

```bash
helm install ralph-job ./charts/ralph \
--set job.repo="git@github.com:owner/repo.git" \
--set job.issueId="42" \
--set job.branch="fix/issue-42" \
--namespace ralph
```

### Values

| Parameter | Description | Default |
|-----------|-------------|---------|
| `job.repo` | Target repository URL (required) | `""` |
| `job.issueId` | GitHub issue ID (required) | `""` |
| `job.branch` | Branch name (required) | `""` |
| `job.issueSource` | Cross-repo issue source | `""` |
| `image.repository` | Container image | `ghcr.io/decocms/ralph` |
| `image.tag` | Image tag | `latest` |
| `claude.maxIterations` | Max loop iterations | `10` |
| `claude.iterationDelay` | Delay between iterations | `5` |
| `workflow.createPullRequest` | Create PR after push | `true` |
| `workflow.postIssueComment` | Post summary comment on issue | `true` |
| `secrets.apiSecretName` | Name of API keys secret | `ralph-secrets` |
| `secrets.sshSecretName` | Name of SSH key secret | `ralph-ssh-key` |

See [charts/ralph/values.yaml](charts/ralph/values.yaml) for all options.

## How It Works

```
┌─────────────────────────────────────────────────────────────┐
│ Ralph Flow │
├─────────────────────────────────────────────────────────────┤
│ │
│ ./ralph.sh │
│ │ │
│ ▼ │
│ 1. Helm install → Creates K8s Job │
│ │
│ Inside the container: │
│ ┌────────────────────────────────────────────────────────┐│
│ │ 2. Fetch issue context from GitHub API ││
│ │ 3. Check write access → Fork if needed ││
│ │ 4. Clone repo (or fork) & create branch ││
│ │ 5. Run Claude Code loop until :::TASK_COMPLETE::: ││
│ │ 6. Commit & push changes ││
│ │ 7. Create Pull Request (via gh CLI) ││
│ │ 8. Post cost summary comment on issue ││
│ └────────────────────────────────────────────────────────┘│
│ │
│ Result: PR opened and issue updated with summary │
│ │
└─────────────────────────────────────────────────────────────┘
```

### Fork Workflow

Ralph automatically detects if you have write access to the target repository:

1. **Write access exists** → Pushes directly to the repo, creates PR within same repo
2. **No write access** → Creates a fork, pushes to fork, creates PR from fork to upstream

This allows Ralph to work on any public repository without requiring collaborator access.

## Cost Tracking

Ralph tracks token usage across all Claude iterations and reports:

- **Input tokens** — Tokens sent to Claude
- **Output tokens** — Tokens generated by Claude
- **Estimated cost** — Based on Claude Sonnet 3.5 pricing

At the end of each run, Ralph:
1. Prints a cost summary to the logs
2. Posts a comment on the GitHub issue with the cost breakdown

Example output:
```
================================================================================
RALPH COST REPORT
================================================================================

Token Usage:
- Input tokens: 15234
- Output tokens: 8921
- Total tokens: 24155

Estimated Cost (Claude Sonnet 3.5 pricing):
- Input cost: $0.0457
- Output cost: $0.1338
- TOTAL COST: $0.1795

================================================================================
```

## The Ralph Wiggum Technique

This project implements the **[Ralph Wiggum AI Loop Technique](https://awesomeclaude.ai/ralph-wiggum)** — an iterative AI development methodology where a simple loop repeatedly feeds Claude a prompt until a completion marker is detected.

```bash
# The core concept:
while :; do cat PROMPT.md | claude ; done
```

**Key principles:**
- **Iteration > Perfection** — Don't aim for perfect on first try
- **Failures Are Data** — Failures are predictable and informative
- **Persistence Wins** — Keep trying until success

## File Structure

```
.
├── ralph.sh # CLI tool - creates K8s jobs via Helm
├── entrypoint.sh # Container entrypoint (runs inside pod)
├── Dockerfile # Container image definition
├── charts/
│ └── ralph/ # Helm chart
│ ├── Chart.yaml
│ ├── values.yaml
│ └── templates/
├── .github/
│ └── workflows/
│ └── release.yaml # CI/CD - publishes to GHCR on tags
└── README.md
```

## CI/CD

The project uses GitHub Actions to automatically build and publish:

- **Docker image** → `ghcr.io/decocms/ralph:TAG`
- **Helm chart** → GitHub Release assets

### Creating a Release

```bash
git tag v1.0.0
git push origin v1.0.0
```

This triggers the workflow to:
1. Build multi-arch Docker image (amd64, arm64)
2. Push to GitHub Container Registry
3. Package and upload Helm chart

## Security

- **Secrets**: Never committed to Git - use Kubernetes secrets
- **Non-root**: Container runs as `node` user (UID 1000)
- **Isolation**: Each job runs in its own pod
- **TTL**: Jobs auto-delete after 1 hour

### Required GitHub Token Permissions

The PAT needs sufficient permissions for forking, pushing, and creating PRs:

- **Public repos**: `public_repo`, `read:org` (for forking)
- **Private repos**: `repo` (full control)

**Fine-grained token scopes** (recommended):
- `contents: write` — Push commits
- `pull_requests: write` — Create PRs
- `issues: write` — Post comments
- `metadata: read` — Read repo info

## Troubleshooting

### Check Job Status

```bash
kubectl get jobs -n ralph -l app.kubernetes.io/name=ralph
kubectl logs -f job/ralph-issue-42 -n ralph
```

### Delete a Job

```bash
helm uninstall ralph-issue-42 -n ralph
```

### SSH Key Issues

```bash
# Verify secret exists
kubectl get secret ralph-ssh-key -n ralph

# Check key format
kubectl get secret ralph-ssh-key -n ralph -o jsonpath='{.data.ssh-private-key}' | base64 -d | head -2
```

## License

MIT License

## Credits

- [Ralph Wiggum Technique](https://awesomeclaude.ai/ralph-wiggum) - The iterative AI loop methodology
- [snarktank/ralph](https://github.com/snarktank/ralph) - Original Ralph pattern
- [Claude Code Docker article](https://medium.com/@dan.avila7/running-claude-code-agents-in-docker-containers-for-complete-isolation-63036a2ef6f4) by Daniel Avila