@emateu/ralph
v1.21.1
Published
GitHub-issue-driven coding agent. Runs one issue at a time locally or in docker/podman sandbox mode.
Downloads
9,645
Readme
ralph
Ralph is a GitHub-issue-driven CLI that runs a coding agent through one task at a time, then pushes a branch and opens a pull request. You give it a feature split into issues; it works the queue and leaves git history, issue links, and a PR as the audit trail.
The GitHub-native take on the Ralph loop — a technique coined by Geoffrey Huntley and popularized by Matt Pocock's aihero guide. The original Ralph re-runs one prompt against a
PRD.mduntil it's done; Ralph runs that same loop on top of GitHub issues, branches, and PRs.
[!IMPORTANT] Ralph starts the selected agent CLI on your machine. That agent can edit any file the process can reach. Run Ralph from a clean repo, watch the first runs, and review the PR before merging. A container boundary is available behind
--sandbox, but local execution is the default.
How it works
Ralph turns a feature into a queue of GitHub issues and works that queue one issue at a time.
You start with a PRD issue — the parent that describes the whole feature —
and split it into n child issues, each a single, small, independently
implementable task. You label the children that are ready with ready-for-agent.
Then you run ralph loop <prd>. Ralph iterates the children: each iteration
takes the lowest-numbered eligible child, starts a fresh agent session scoped
to exactly that one issue, and lets the agent read the repo, implement the
task, run checks, and commit with Closes #N. Ralph — not the agent — pushes
the branch and opens or updates one rolling pull request for the whole PRD.
It repeats until no eligible child is left.
There is no second state store. Progress is read straight from the branch's git
history (a child is "done" once its Closes #N is committed on the branch), and
eligibility is the ready-for-agent label. The rolling PR is the human review
gate: the children stay open until you merge it, and merging closes them all.
PRD #42 (parent issue: "Build account settings")
│
├── #43 Email preferences form ┐
├── #44 Persist settings │ child issues,
└── #45 Settings page tests ┘ labelled ready-for-agent
│ ralph loop 42 --agent opencode
▼
┌─ loop: one child per iteration, lowest # first ───────────┐
│ │
│ fresh agent session ──► implements one issue │
│ │ │
│ ▼ │
│ commit "… Closes #43" ──► push ──► rolling PR │
│ │
└────────────── repeat until no child is left ────────────┘
│
▼
branch: ralph/loop-42-<scope> (scope = agent + model + params)
PR: one rolling PR for #42 → merging it closes #43 #44 #45Each child gets a fresh session, so context never drifts across tasks; the
branch is the only memory channel between them — a later child sees earlier work
through git log and the current files.
The workflow
Ralph is one step in a larger operator loop. It consumes issues that already exist; it does not plan the work for you.
- Write a PRD issue describing the feature.
- Split it into child issues — small, independently implementable tasks
linked back to the PRD, and labelled
ready-for-agentwhen they're ready. - Run
ralph loop <prd>and watch the first iterations. - Review the rolling PR like any other PR.
- Merge when satisfied — that closes the children.
Steps 1–2 are yours to do however you like. Ralph can install two optional skills that help draft them from a conversation:
ralph skills install # adds to-prd, to-issues, grill-with-docs, grill-meto-prd drafts a PRD issue, and to-issues breaks it into child issues whose
shape Ralph can discover. They run on your host before Ralph; Ralph never
requires them at runtime.
Requirements
- Node.js 22+.
- A local clone of the target repo with an
originremote, and push access. ghinstalled, authenticated, and able to read issues and open PRs.- One supported agent CLI installed and authenticated:
claude,opencode,codex, orcursor-agent.
Check the basics before your first run — every agent has a built-in default
model, so --model is optional:
gh auth status # GitHub auth is good
git remote -v # origin points at the target repo
ralph doctor --agent opencode # repo access, auth, and agent readinessInstall
npm install -g @emateu/ralph@latest
ralph --versionFor a one-off run without a global install:
npx @emateu/ralph --helpOnce installed globally, update in place with ralph upgrade.
Quickstart
From inside the repo you want Ralph to work on:
# One child issue from PRD #42. This is a real run: it can edit code,
# push a branch, and open a PR. It is NOT a dry run.
ralph loop 42 --agent opencode --max 1
# Continue the loop until the queue is empty (or the default cap of 100).
ralph loop 42 --agent opencode--max 1 is useful for the first pass: it limits Ralph to a single child so you
can watch one full iteration before letting it run the rest.
Preparing issues
Ralph works with two kinds of issue:
- PRD issue — the parent that describes the larger feature.
- Child issue — one implementable task.
A child issue is eligible when it is open, labelled ready-for-agent
(by default), and linked to the PRD. Ralph discovers children from GitHub's
native sub-issue relationship first, then unions in any markdown parent links
and child references listed in the PRD body.
The most reliable child-issue shape is:
## Parent
[#42 Build account settings](https://github.com/OWNER/REPO/issues/42)
## Task
Implement the email preferences form.
## Acceptance Criteria
- Users can toggle product updates.
- The setting persists after reload.
- Existing tests still pass.The parent link can be a Markdown issue link like [#42 ...] or any GitHub
issue URL containing /issues/42. If the PRD body lists children such as #43,
#44, #45, Ralph validates them and, by default, adds the missing ## Parent
section and links them as native sub-issues before running. Pass --no-normalize
to keep the run read-only against issue bodies.
The two modes
Loop mode — ralph loop <prd> — is the batch workflow above: all completed
children land on one branch and one rolling PR for the PRD.
Standalone issue mode — ralph issue <ref> — handles work that should get
its own PR instead of joining a PRD's rolling PR. The reference can be a number,
a #-prefixed number, or a full issue URL:
ralph issue 16 --agent opencode
ralph issue '#16' --agent opencode
ralph issue https://github.com/OWNER/REPO/issues/16 --agent opencodeIt creates ralph/issue-16-<scope>, runs the agent on that issue, and opens a
PR with Closes #16 in the body. Inclusive ranges run one session per open
issue (skipping closed ones, stopping on the first failure):
ralph issue 16..18 --agent opencode
ralph issue '#16..#18' --agent opencode --max 2Both modes are read-only against GitHub issues while they run: Ralph never claims, comments, or closes. Issues close only when you merge a PR.
Agents
Pick the agent with --agent (or RALPH_AGENT). Each ships a validated default
model and reasoning level, so --model and --agent-param are optional.
| Agent | CLI Ralph starts | Default model | Reasoning param (default) |
|---|---|---|---|
| claude | claude | claude-sonnet-4-6 | effort (max) |
| opencode | opencode | opencode-go/qwen3.6-plus | variant (max) |
| codex | codex | gpt-5.5 | effort (high) |
| cursor | cursor-agent (or agent) | composer-2.5 | — |
Override the model or params with repeatable flags:
ralph loop 42 --agent claude --agent-param effort=high # change reasoning
ralph loop 42 --agent opencode --model opencode-go/qwen3.7-max # change the modelOnly params the selected agent uses are forwarded. Strict params (claude /
codex effort) are validated against a per-agent spec and fail fast on an
unsupported value; passthrough params (opencode variant) are forwarded
unvalidated.
Run scoping and bake-offs
Every run is identified by its agent + model + params, rendered as a
readable slug. The branch, worktree, log, PR, and container all derive from it.
For example, ralph loop 42 --agent opencode --model qwen3.7-max produces branch
ralph/loop-42-opencode-qwen3.7-max-variant-max.
Two consequences fall out of this:
- Resume — re-running the same configuration resumes the same branch and skips children it already finished (read from git history). A crash mid-run is resumable; a finished run is a no-op.
- Bake-offs — running the same PRD with a different model produces a separate branch and PR, so you can run several models concurrently and compare the PRs before merging one.
See docs/RUN-MODEL.md for the full state model.
Commands
ralph loop <prd-num> [--agent <name>] [--model <name>] [--max N]
[--agent-param k=v] [--label <name>] [--gh-account <user>]
[--base-branch <branch>] [--tool-output] [--debug]
[--no-normalize] [--scan-by-label] [--sandbox]
Run the loop over a PRD's children. Default --max cap is 100.
ralph issue <ref> [--agent <name>] [--model <name>] [--agent-param k=v]
[--gh-account <user>] [--base-branch <branch>]
[--tool-output] [--debug] [--sandbox]
Run one standalone issue. <ref> is 16, #16, or a GitHub issue URL.
ralph issue <from>..<to> [--max N] ...
Run one standalone session per issue in an inclusive range.
ralph doctor [--agent <name>] [--model <name>] [--gh-account <user>] [--sandbox]
Check repo, gh auth, config, optional skills, and agent readiness.
ralph skills install Install the optional pre-run operator skills.
ralph sandbox setup --agent <name> Build a sandbox image (only for --sandbox).
ralph upgrade [version|tag] [--check] [--pm <npm|pnpm|yarn|bun>]
Update ralph to the latest npm release. `update` is an alias.
ralph --version
ralph --help Run `ralph <command> --help` for command-specific help.--no-normalize skips the pre-flight body edits (scan + validate still run).
--scan-by-label skips the PRD-body scan entirely and discovers only labelled
children that already link back to the PRD.
Configuration
Configuration is optional. Pass flags every time, use shell env vars, or create
~/.config/ralph/config.env. Precedence is:
CLI flags and shell env > ~/.config/ralph/config.env > built-in defaults| Variable | Purpose |
|---|---|
| RALPH_DEFAULT_AGENT | Default agent when --agent is omitted. |
| RALPH_AGENT | Agent for this invocation (same as --agent). |
| RALPH_MODEL | Model for this invocation (same as --model). |
| RALPH_AGENT_PARAMS | Comma-separated params, e.g. effort=high,variant=max. |
| RALPH_LABEL | Ready label for child issues. Default ready-for-agent. |
| RALPH_BASE_BRANCH | Base branch for generated PRs. Default main. |
| RALPH_GH_ACCOUNT | Use a specific gh account without changing the global active one. |
| GH_TOKEN | Explicit GitHub token. If absent, Ralph lets gh provide auth. |
| RALPH_TMP_BASE | Base dir for temp/runtime paths. Default /tmp/ralph. |
| RALPH_LOG_TOOL_OUTPUT | 1 logs each tool's stdout/stderr (same as --tool-output). |
| RALPH_DEBUG | 1 prints diagnostic detail on error (same as --debug). |
Example:
mkdir -p ~/.config/ralph
cat > ~/.config/ralph/config.env <<'EOF'
RALPH_DEFAULT_AGENT=opencode
RALPH_LABEL=ready-for-agent
RALPH_BASE_BRANCH=main
EOFAgent auth is handled by the agent CLIs themselves. If an agent reads env vars
like ANTHROPIC_API_KEY, OPENCODE_API_KEY, or CURSOR_API_KEY, Ralph inherits
them when it starts the agent process.
Sandbox (optional)
Pass --sandbox to run the same flow with the agent inside a container Ralph
manages (Docker by default; Podman via RALPH_CONTAINER_RUNTIME=podman). Build
the image once per agent first:
ralph sandbox setup --agent claude
ralph issue 16 --sandbox --agent claudeThe container bind-mounts the real worktree, so commits still land on your host
branch and use the normal PR flow. See docs/SANDBOX.md.
Upgrading
ralph upgrade # install the latest version
ralph upgrade --check # report whether a newer version exists; install nothing
ralph upgrade 1.9.0 # install a specific version or dist-tag (e.g. next)ralph upgrade detects how Ralph was installed (npm, pnpm, yarn, or bun) and
runs that package manager's global install. It never uses sudo; if the global
install fails on permissions, it prints the exact command to run yourself. Force
the installer with --pm <name> if auto-detection guesses wrong. ralph update
is an alias.
Troubleshooting
| Symptom | What to do |
|---|---|
| No agent configured | Pass --agent <name>, or set RALPH_AGENT / RALPH_DEFAULT_AGENT. |
| gh auth fails | Run gh auth status, then gh auth login. |
| Could not resolve to a Repository | The active gh account may lack access. Retry with --gh-account <user>. |
| Agent CLI not found | Install and log in to the selected agent CLI, then rerun. |
| 0 children eligible | Confirm children are open, linked to the PRD, and labelled ready-for-agent (or your RALPH_LABEL). |
| A loop stops after one child | Check for --max 1, an empty queue, or a failed task. |
| Agent produced no commits | Ralph stops and leaves issue state unchanged. Inspect .ralph/logs/ and rerun after fixing the cause. |
| Existing worktree blocks a run | Inspect .ralph/worktrees/. Ralph preserves a worktree with uncommitted changes. |
Working on Ralph itself
This repo uses pnpm for package scripts and bun for bundling.
pnpm install
pnpm run typecheck # tsc --noEmit (the bun build does NOT type-check)
pnpm test
pnpm run build
node dist/cli.mjs --helpThe test suite mocks GitHub and agent interactions; it needs no real GitHub
credentials, network access, or agent session. For the design and state model,
read docs/RUN-MODEL.md and
docs/METHODOLOGY.md.
