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.
- 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
- Kubernetes cluster with
kubectlconfigured - Helm installed
- GitHub Personal Access Token
- Anthropic API Key
- SSH key for Git push access
# Add the chart repository (or clone this repo)
git clone https://github.com/decocms/ralph.git
cd ralph# 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# 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./ralph.sh <target-repo> <issue> <branch-name>The <issue> 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
# 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| 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 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| 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 for all options.
┌─────────────────────────────────────────────────────────────┐
│ Ralph Flow │
├─────────────────────────────────────────────────────────────┤
│ │
│ ./ralph.sh <repo> <issue> <branch> │
│ │ │
│ ▼ │
│ 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 │
│ │
└─────────────────────────────────────────────────────────────┘
Ralph automatically detects if you have write access to the target repository:
- Write access exists → Pushes directly to the repo, creates PR within same repo
- 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.
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:
- Prints a cost summary to the logs
- 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
================================================================================
This project implements the Ralph Wiggum AI Loop Technique — an iterative AI development methodology where a simple loop repeatedly feeds Claude a prompt until a completion marker is detected.
# The core concept:
while :; do cat PROMPT.md | claude ; doneKey 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
.
├── 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
The project uses GitHub Actions to automatically build and publish:
- Docker image →
ghcr.io/decocms/ralph:TAG - Helm chart → GitHub Release assets
git tag v1.0.0
git push origin v1.0.0This triggers the workflow to:
- Build multi-arch Docker image (amd64, arm64)
- Push to GitHub Container Registry
- Package and upload Helm chart
- Secrets: Never committed to Git - use Kubernetes secrets
- Non-root: Container runs as
nodeuser (UID 1000) - Isolation: Each job runs in its own pod
- TTL: Jobs auto-delete after 1 hour
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 commitspull_requests: write— Create PRsissues: write— Post commentsmetadata: read— Read repo info
kubectl get jobs -n ralph -l app.kubernetes.io/name=ralph
kubectl logs -f job/ralph-issue-42 -n ralphhelm uninstall ralph-issue-42 -n ralph# 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 -2MIT License
- Ralph Wiggum Technique - The iterative AI loop methodology
- snarktank/ralph - Original Ralph pattern
- Claude Code Docker article by Daniel Avila