ralph-cursor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +724 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +60 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +69 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +162 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/logs.d.ts +3 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +28 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/loop.d.ts +3 -0
- package/dist/commands/loop.d.ts.map +1 -0
- package/dist/commands/loop.js +186 -0
- package/dist/commands/loop.js.map +1 -0
- package/dist/commands/once.d.ts +3 -0
- package/dist/commands/once.d.ts.map +1 -0
- package/dist/commands/once.js +187 -0
- package/dist/commands/once.js.map +1 -0
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +328 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +33 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/task.d.ts +3 -0
- package/dist/commands/task.d.ts.map +1 -0
- package/dist/commands/task.js +161 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/lib/config.d.ts +8 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +48 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/last-run.d.ts +12 -0
- package/dist/lib/last-run.d.ts.map +1 -0
- package/dist/lib/last-run.js +33 -0
- package/dist/lib/last-run.js.map +1 -0
- package/dist/lib/ralph-dir.d.ts +6 -0
- package/dist/lib/ralph-dir.d.ts.map +1 -0
- package/dist/lib/ralph-dir.js +96 -0
- package/dist/lib/ralph-dir.js.map +1 -0
- package/dist/lib/spawn.d.ts +11 -0
- package/dist/lib/spawn.d.ts.map +1 -0
- package/dist/lib/spawn.js +29 -0
- package/dist/lib/spawn.js.map +1 -0
- package/dist/lib/tail.d.ts +9 -0
- package/dist/lib/tail.d.ts.map +1 -0
- package/dist/lib/tail.js +58 -0
- package/dist/lib/tail.js.map +1 -0
- package/dist/loop/index.d.ts +32 -0
- package/dist/loop/index.d.ts.map +1 -0
- package/dist/loop/index.js +165 -0
- package/dist/loop/index.js.map +1 -0
- package/dist/loop/prompt.d.ts +5 -0
- package/dist/loop/prompt.d.ts.map +1 -0
- package/dist/loop/prompt.js +77 -0
- package/dist/loop/prompt.js.map +1 -0
- package/dist/loop/retry.d.ts +22 -0
- package/dist/loop/retry.d.ts.map +1 -0
- package/dist/loop/retry.js +65 -0
- package/dist/loop/retry.js.map +1 -0
- package/dist/parallel/lock.d.ts +7 -0
- package/dist/parallel/lock.d.ts.map +1 -0
- package/dist/parallel/lock.js +110 -0
- package/dist/parallel/lock.js.map +1 -0
- package/dist/parallel/merge.d.ts +5 -0
- package/dist/parallel/merge.d.ts.map +1 -0
- package/dist/parallel/merge.js +39 -0
- package/dist/parallel/merge.js.map +1 -0
- package/dist/parallel/run.d.ts +18 -0
- package/dist/parallel/run.d.ts.map +1 -0
- package/dist/parallel/run.js +407 -0
- package/dist/parallel/run.js.map +1 -0
- package/dist/parallel/worktree.d.ts +12 -0
- package/dist/parallel/worktree.d.ts.map +1 -0
- package/dist/parallel/worktree.js +69 -0
- package/dist/parallel/worktree.js.map +1 -0
- package/dist/stream-parser/index.d.ts +18 -0
- package/dist/stream-parser/index.d.ts.map +1 -0
- package/dist/stream-parser/index.js +248 -0
- package/dist/stream-parser/index.js.map +1 -0
- package/dist/task-parser/index.d.ts +21 -0
- package/dist/task-parser/index.d.ts.map +1 -0
- package/dist/task-parser/index.js +195 -0
- package/dist/task-parser/index.js.map +1 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
# Ralph Wiggum for Cursor
|
|
2
|
+
|
|
3
|
+
An implementation of [Geoffrey Huntley's Ralph Wiggum technique](https://ghuntley.com/ralph/) for Cursor, enabling autonomous AI development with deliberate context management.
|
|
4
|
+
|
|
5
|
+
> "That's the beauty of Ralph - the technique is deterministically bad in an undeterministic world."
|
|
6
|
+
|
|
7
|
+
## What is Ralph?
|
|
8
|
+
|
|
9
|
+
Ralph is a technique for autonomous AI development that treats LLM context like memory:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
while :; do cat PROMPT.md | agent ; done
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The same prompt is fed repeatedly to an AI agent. Progress persists in **files and git**, not in the LLM's context window. When context fills up, you get a fresh agent with fresh context.
|
|
16
|
+
|
|
17
|
+
### The malloc/free Problem
|
|
18
|
+
|
|
19
|
+
In traditional programming:
|
|
20
|
+
- `malloc()` allocates memory
|
|
21
|
+
- `free()` releases memory
|
|
22
|
+
|
|
23
|
+
In LLM context:
|
|
24
|
+
- Reading files, tool outputs, conversation = `malloc()`
|
|
25
|
+
- **There is no `free()`** - context cannot be selectively released
|
|
26
|
+
- Only way to free: start a new conversation
|
|
27
|
+
|
|
28
|
+
This creates two problems:
|
|
29
|
+
|
|
30
|
+
1. **Context pollution** - Failed attempts, unrelated code, and mixed concerns accumulate and confuse the model
|
|
31
|
+
2. **The gutter** - Once polluted, the model keeps referencing bad context. Like a bowling ball in the gutter, there's no saving it.
|
|
32
|
+
|
|
33
|
+
**Ralph's solution:** Deliberately rotate to fresh context before pollution builds up. State lives in files and git, not in the LLM's memory.
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
39
|
+
β ralph-cursor run / ralph-cursor loop β
|
|
40
|
+
β β β
|
|
41
|
+
β ββββββββββββββ΄βββββββββββββ β
|
|
42
|
+
β βΌ βΌ β
|
|
43
|
+
β [interactive] [fallback] β
|
|
44
|
+
β Model selection Simple prompts β
|
|
45
|
+
β Max iterations β
|
|
46
|
+
β Options (branch, PR) β
|
|
47
|
+
β β β β
|
|
48
|
+
β ββββββββββββββ¬βββββββββββββ β
|
|
49
|
+
β βΌ β
|
|
50
|
+
β cursor-agent -p --force --output-format stream-json β
|
|
51
|
+
β β β
|
|
52
|
+
β βΌ β
|
|
53
|
+
β stream parser (Node) β
|
|
54
|
+
β β β β
|
|
55
|
+
β ββββββββββββββββββ΄βββββββββ΄βββββββββββββββββ β
|
|
56
|
+
β βΌ βΌ β
|
|
57
|
+
β .ralph/ Signals β
|
|
58
|
+
β βββ activity.log (tool calls) βββ WARN at 70k β
|
|
59
|
+
β βββ errors.log (failures) βββ ROTATE at 80kβ
|
|
60
|
+
β βββ progress.md (agent writes) βββ COMPLETE β
|
|
61
|
+
β βββ guardrails.md (lessons learned) βββ GUTTER β
|
|
62
|
+
β βββ tasks.yaml (cached task state) βββ DEFER β
|
|
63
|
+
β β
|
|
64
|
+
β When ROTATE β fresh context, continue from git β
|
|
65
|
+
β When DEFER β exponential backoff, retry same task β
|
|
66
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Key features:**
|
|
70
|
+
- **Interactive setup** - Prompts for model selection and options (ralph-cursor run)
|
|
71
|
+
- **Accurate token tracking** - Parser counts actual bytes from every file read/write
|
|
72
|
+
- **Gutter detection** - Detects when agent is stuck (same command failed 3x, file thrashing)
|
|
73
|
+
- **Rate limit handling** - Detects rate limits/network errors, waits with exponential backoff
|
|
74
|
+
- **Task caching** - YAML backend with mtime invalidation for efficient task parsing
|
|
75
|
+
- **Learning from failures** - Agent updates `.ralph/guardrails.md` with lessons
|
|
76
|
+
- **State in git** - Commits frequently so next agent picks up from git history
|
|
77
|
+
- **Branch/PR workflow** - Optionally work on a branch and open PR when complete
|
|
78
|
+
|
|
79
|
+
## Prerequisites
|
|
80
|
+
|
|
81
|
+
| Requirement | Check | How to Set Up |
|
|
82
|
+
|-------------|-------|---------------|
|
|
83
|
+
| **Git repo** | `git status` works | `git init` |
|
|
84
|
+
| **cursor-agent CLI** | `which cursor-agent` | `curl https://cursor.com/install -fsS \| bash` |
|
|
85
|
+
| **Node.js 18+** (for CLI) | `node -v` | [nodejs.org](https://nodejs.org/) |
|
|
86
|
+
|
|
87
|
+
## Quick Start (Node CLI)
|
|
88
|
+
|
|
89
|
+
**Option A β npx (no install):**
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cd your-project
|
|
93
|
+
npx ralph-cursor init # create .ralph/ and RALPH_TASK.md template
|
|
94
|
+
# Edit RALPH_TASK.md with your task and success criteria
|
|
95
|
+
npx ralph-cursor run # interactive run
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Option B β install globally**
|
|
99
|
+
|
|
100
|
+
From npm (if the package is published):
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
npm install -g ralph-cursor
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
From the repo (development or before publishing):
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cd /path/to/ralph-cursor
|
|
110
|
+
bun run build
|
|
111
|
+
npm install -g .
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Or use `npm link` from the repo, then run `ralph-cursor` from any project. If `ralph-cursor --help` prints nothing, another binary may be in your PATH first; run `$(npm root -g)/.bin/ralph-cursor --help` to use the linked CLI.
|
|
115
|
+
|
|
116
|
+
**Option C β from repo (dev):**
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
cd ralph-cursor
|
|
120
|
+
bun install
|
|
121
|
+
bun run build
|
|
122
|
+
# Run locally from repo:
|
|
123
|
+
bun run ralph-cursor init
|
|
124
|
+
bun run ralph-cursor run # or: node dist/cli.js run
|
|
125
|
+
bun run ralph-cursor loop -y
|
|
126
|
+
# Or link globally: npm link, then in any project run ralph-cursor init, ralph-cursor run.
|
|
127
|
+
# If `ralph-cursor` does nothing (another binary in PATH), run from repo: node dist/cli.js --help
|
|
128
|
+
npm link
|
|
129
|
+
cd /path/to/your-project
|
|
130
|
+
ralph-cursor init
|
|
131
|
+
ralph-cursor run
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
From another project without linking: `node /path/to/ralph-cursor/dist/cli.js init` (and `run`, `loop`, etc.).
|
|
135
|
+
|
|
136
|
+
**Publishing:** `bun run build && bun test` then `npm version patch` (or minor/major) and `npm publish`. `prepublishOnly` runs build automatically.
|
|
137
|
+
|
|
138
|
+
**CLI commands:**
|
|
139
|
+
|
|
140
|
+
| Command | Description |
|
|
141
|
+
|---------|-------------|
|
|
142
|
+
| `ralph-cursor run` | Interactive run (prompts for model/iterations, optional single iteration first, then loop). Options: `--branch`, `--pr`, `-y`. |
|
|
143
|
+
| `ralph-cursor once` | Single iteration (no loop). |
|
|
144
|
+
| `ralph-cursor loop` | Non-interactive loop with flags (`-n`, `-m`, `--task`, `--branch`, `--pr`, `--parallel`, etc.). |
|
|
145
|
+
| `ralph-cursor task list` | List all tasks (id, status, description). |
|
|
146
|
+
| `ralph-cursor task next` | Print next incomplete task (id\|status\|description). |
|
|
147
|
+
| `ralph-cursor task complete <id>` | Mark task complete by id (e.g. `line_5`). |
|
|
148
|
+
| `ralph-cursor task incomplete <id>` | Mark task incomplete by id. |
|
|
149
|
+
| `ralph-cursor task parse` | Parse task file and update `.ralph/tasks.yaml`. |
|
|
150
|
+
| `ralph-cursor task export` | Print task cache as YAML (same as `.ralph/tasks.yaml`). |
|
|
151
|
+
| `ralph-cursor status` | Print task summary (done/total, last iteration). |
|
|
152
|
+
| `ralph-cursor logs` | Tail `activity.log` (or `--errors` for `errors.log`); `-n N`, `--no-follow`. Cross-platform (no `tail`). |
|
|
153
|
+
| `ralph-cursor init` | Create `.ralph/` and optional `RALPH_TASK.md` template. |
|
|
154
|
+
| `ralph-cursor doctor` | Check environment (cursor-agent, git, task file, .ralph writable). |
|
|
155
|
+
|
|
156
|
+
**Global flags:** `-V, --version` (print version), `-v, --verbose` (log each stream-json line to stderr with `[ralph]` prefix for debugging).
|
|
157
|
+
|
|
158
|
+
**Exit codes:** `0` = success; `1` = failure or prerequisite check failed (no task file, not git, cursor-agent missing, gutter, max iterations); `2` = usage error (e.g. invalid args). See table below for per-command behaviour.
|
|
159
|
+
|
|
160
|
+
| Command | 0 | 1 | 2 |
|
|
161
|
+
|---------|---|---|---|
|
|
162
|
+
| `run`, `loop`, `once` | Task complete or ran successfully | Prereq failed (no task file, not git, no cursor-agent), gutter, max iterations, or loop ended without completion | Usage (e.g. --pr without --branch) |
|
|
163
|
+
| `task list/next/complete/incomplete` | OK | Invalid task id / file error | No task file / workspace not found |
|
|
164
|
+
| `status`, `logs` | OK | β | No task file / .ralph not initialized |
|
|
165
|
+
| `init` | .ralph created | β | β |
|
|
166
|
+
| `doctor` | All checks passed | β | cursor-agent missing, not git, task file missing, or .ralph not writable |
|
|
167
|
+
|
|
168
|
+
**Config:** Optional `.ralph/config.json` (and env overrides):
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"warn_threshold": 70000,
|
|
173
|
+
"rotate_threshold": 80000,
|
|
174
|
+
"default_model": "opus-4.5-thinking",
|
|
175
|
+
"max_iterations": 20
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Env (override config): `RALPH_WARN_THRESHOLD`, `RALPH_ROTATE_THRESHOLD`, `RALPH_MODEL`, `MAX_ITERATIONS`. `WARN_THRESHOLD` and `ROTATE_THRESHOLD` are also supported. CLI flags override config and env.
|
|
180
|
+
|
|
181
|
+
**Environment variables (reference):**
|
|
182
|
+
|
|
183
|
+
| Variable | Purpose |
|
|
184
|
+
|----------|---------|
|
|
185
|
+
| `RALPH_WARN_THRESHOLD` | Token count at which to emit WARN (default 70000). |
|
|
186
|
+
| `RALPH_ROTATE_THRESHOLD` | Token count at which to rotate context (default 80000). |
|
|
187
|
+
| `RALPH_MODEL` | Default model for cursor-agent (e.g. `opus-4.5-thinking`). |
|
|
188
|
+
| `MAX_ITERATIONS` | Default max loop iterations. |
|
|
189
|
+
| `RALPH_TASK_FILE` | Path to task file (default `RALPH_TASK.md`). |
|
|
190
|
+
| `RALPH_VERBOSE` | Set to `1` to log each stream-json line to stderr (same as `-v`). |
|
|
191
|
+
| `WARN_THRESHOLD`, `ROTATE_THRESHOLD` | Same as `RALPH_*`. |
|
|
192
|
+
| `DEFAULT_GROUP`, `RALPH_DEFAULT_GROUP` | Default parallel group for tasks without `<!-- group: N -->` (default 999999). |
|
|
193
|
+
|
|
194
|
+
**Iteration:** The CLI resumes from `.ralph/.iteration` (incremented each loop run). To force a fresh start, delete `.ralph/.iteration` or set it to `0`.
|
|
195
|
+
|
|
196
|
+
**Parallel mode:** `ralph-cursor loop --parallel` runs multiple agents in git worktrees (one per task or batch). Uses `.ralph-worktrees/`, lock in `.ralph/locks/parallel.lock`, merge phase after each group. Options: `--max-parallel N`, `--branch` (integration branch), `--pr` (create PR when done), `--no-merge` (skip auto-merge). Requires RALPH_TASK.md committed and tasks with `<!-- group: N -->` for grouping.
|
|
197
|
+
|
|
198
|
+
### Troubleshooting
|
|
199
|
+
|
|
200
|
+
| Issue | What to do |
|
|
201
|
+
|-------|------------|
|
|
202
|
+
| `cursor-agent not found` | Install: `curl https://cursor.com/install -fsS \| bash` (or see Cursor docs). Run `ralph-cursor doctor` to verify. |
|
|
203
|
+
| `No task file` / exit 2 | Run `ralph-cursor init` in project root, then edit `RALPH_TASK.md` with your task and success criteria. |
|
|
204
|
+
| Agent seems stuck (same error repeatedly) | Ralph may emit GUTTER and stop. Check `.ralph/errors.log` and `.ralph/guardrails.md`; refine task or guardrails and run again. |
|
|
205
|
+
| Rate limits / 429 / DEFER | Ralph backs off automatically. If it persists, reduce concurrency or switch model; set thresholds in `.ralph/config.json` if needed. |
|
|
206
|
+
| Context too large (WARN/ROTATE) | Default 70k/80k token thresholds trigger rotation. Adjust `warn_threshold` / `rotate_threshold` in config or env. |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Quick Start
|
|
211
|
+
|
|
212
|
+
In your project root:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
npx ralph-cursor init
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
This creates `.ralph/` (progress.md, guardrails.md, activity.log, errors.log) and `RALPH_TASK.md` if missing. Then:
|
|
219
|
+
|
|
220
|
+
### 1. Define Your Task
|
|
221
|
+
|
|
222
|
+
Edit `RALPH_TASK.md`:
|
|
223
|
+
|
|
224
|
+
```markdown
|
|
225
|
+
---
|
|
226
|
+
task: Build a REST API
|
|
227
|
+
test_command: "pnpm test"
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
# Task: REST API
|
|
231
|
+
|
|
232
|
+
Build a REST API with user management.
|
|
233
|
+
|
|
234
|
+
## Success Criteria
|
|
235
|
+
|
|
236
|
+
1. [ ] GET /health returns 200
|
|
237
|
+
2. [ ] POST /users creates a user
|
|
238
|
+
3. [ ] GET /users/:id returns user
|
|
239
|
+
4. [ ] All tests pass
|
|
240
|
+
|
|
241
|
+
## Context
|
|
242
|
+
|
|
243
|
+
- Use Express.js
|
|
244
|
+
- Store users in memory (no database needed)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Important:** Use `[ ]` checkboxes. Ralph tracks completion by counting unchecked boxes.
|
|
248
|
+
|
|
249
|
+
### 2. Start the Loop
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
npx ralph-cursor run
|
|
253
|
+
# or: ralph-cursor loop -y (non-interactive)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Ralph will:
|
|
257
|
+
1. Show interactive prompts for model and options (or use `ralph-cursor loop` with flags)
|
|
258
|
+
2. Run `cursor-agent` with your task
|
|
259
|
+
3. Parse output in real-time, tracking token usage
|
|
260
|
+
4. At 70k tokens: warn agent to wrap up current work
|
|
261
|
+
5. At 80k tokens: rotate to fresh context
|
|
262
|
+
6. Repeat until all `[ ]` are `[x]` (or max iterations reached)
|
|
263
|
+
|
|
264
|
+
### 3. Monitor Progress
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
ralph-cursor logs
|
|
268
|
+
# or: tail -f .ralph/activity.log
|
|
269
|
+
|
|
270
|
+
# Example output:
|
|
271
|
+
# [12:34:56] π’ READ src/index.ts (245 lines, ~24.5KB)
|
|
272
|
+
# [12:34:58] π’ WRITE src/routes/users.ts (50 lines, 2.1KB)
|
|
273
|
+
# [12:35:01] π’ SHELL pnpm test β exit 0
|
|
274
|
+
# [12:35:10] π’ TOKENS: 45,230 / 80,000 (56%) [read:30KB write:5KB assist:10KB shell:0KB]
|
|
275
|
+
|
|
276
|
+
# Check for failures
|
|
277
|
+
cat .ralph/errors.log
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Commands (Node CLI)
|
|
281
|
+
|
|
282
|
+
| Command | Description |
|
|
283
|
+
|---------|-------------|
|
|
284
|
+
| `ralph-cursor run` | **Primary** - Interactive setup + run loop |
|
|
285
|
+
| `ralph-cursor once` | Test single iteration before going AFK |
|
|
286
|
+
| `ralph-cursor loop` | CLI mode for scripting (see flags below) |
|
|
287
|
+
| `ralph-cursor init` | Create .ralph/ and RALPH_TASK.md template |
|
|
288
|
+
|
|
289
|
+
### ralph-cursor loop flags (scripting/CI)
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
ralph-cursor loop [options] [workspace]
|
|
293
|
+
|
|
294
|
+
Options:
|
|
295
|
+
-n, --iterations N Max iterations (default: 20)
|
|
296
|
+
-m, --model MODEL Model to use (default: opus-4.5-thinking)
|
|
297
|
+
--branch NAME Sequential: create/work on branch; Parallel: integration branch name
|
|
298
|
+
--pr Sequential: open PR (requires --branch); Parallel: open ONE integration PR (branch optional)
|
|
299
|
+
--parallel Run tasks in parallel with worktrees
|
|
300
|
+
--max-parallel N Max parallel agents (default: 3)
|
|
301
|
+
--no-merge Skip auto-merge in parallel mode
|
|
302
|
+
-y, --yes Skip confirmation prompt
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Examples:**
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# Scripted PR workflow
|
|
309
|
+
ralph-cursor loop --branch feature/api --pr -y
|
|
310
|
+
|
|
311
|
+
# Use a different model with more iterations
|
|
312
|
+
ralph-cursor loop -n 50 -m gpt-5.2-high
|
|
313
|
+
|
|
314
|
+
# Run 4 agents in parallel
|
|
315
|
+
ralph-cursor loop --parallel --max-parallel 4
|
|
316
|
+
|
|
317
|
+
# Parallel: keep branches separate
|
|
318
|
+
ralph-cursor loop --parallel --no-merge
|
|
319
|
+
|
|
320
|
+
# Parallel: merge into an integration branch + open ONE PR
|
|
321
|
+
ralph-cursor loop --parallel --max-parallel 5 --branch feature/multi-task --pr
|
|
322
|
+
|
|
323
|
+
# Parallel: open ONE PR using an auto-named integration branch
|
|
324
|
+
ralph-cursor loop --parallel --max-parallel 5 --pr
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Parallel Execution
|
|
328
|
+
|
|
329
|
+
Ralph can run multiple agents concurrently, each in an isolated git worktree.
|
|
330
|
+
|
|
331
|
+
### Starting Parallel Mode
|
|
332
|
+
|
|
333
|
+
**Via interactive run:**
|
|
334
|
+
```bash
|
|
335
|
+
ralph-cursor run
|
|
336
|
+
# Choose "Run in parallel mode?" and set max parallel agents when prompted
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Via CLI (scripting/CI):**
|
|
340
|
+
```bash
|
|
341
|
+
# Run 3 agents in parallel (default)
|
|
342
|
+
ralph-cursor loop --parallel
|
|
343
|
+
|
|
344
|
+
# Run 10 agents in parallel (no hard cap)
|
|
345
|
+
ralph-cursor loop --parallel --max-parallel 10
|
|
346
|
+
|
|
347
|
+
# Keep branches separate (no auto-merge)
|
|
348
|
+
ralph-cursor loop --parallel --no-merge
|
|
349
|
+
|
|
350
|
+
# Merge into an integration branch (no PR)
|
|
351
|
+
ralph-cursor loop --parallel --max-parallel 5 --branch feature/multi-task
|
|
352
|
+
|
|
353
|
+
# Merge into an integration branch and open ONE PR
|
|
354
|
+
ralph-cursor loop --parallel --max-parallel 5 --branch feature/multi-task --pr
|
|
355
|
+
|
|
356
|
+
# Open ONE PR using an auto-named integration branch
|
|
357
|
+
ralph-cursor loop --parallel --max-parallel 5 --pr
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
> **Note:** There's no hard limit on `--max-parallel`. The practical limit depends on your machine's resources and API rate limits.
|
|
361
|
+
|
|
362
|
+
### Integration branch + single PR
|
|
363
|
+
|
|
364
|
+
Parallel `--pr` creates **one integration branch** (either your `--branch NAME` or an auto-named `ralph/parallel-<run_id>`), merges all successful agent branches into it, then opens **one PR** back to the base branch.
|
|
365
|
+
|
|
366
|
+
This avoids βone PR per taskβ spam while keeping agents isolated.
|
|
367
|
+
|
|
368
|
+
### How Parallel Mode Works
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
372
|
+
β Parallel Execution Flow β
|
|
373
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
|
|
374
|
+
β β
|
|
375
|
+
β RALPH_TASK.md β
|
|
376
|
+
β - [ ] Task A β
|
|
377
|
+
β - [ ] Task B ββββββββββββββββββββββββββββ β
|
|
378
|
+
β - [ ] Task C ββββΆ β Create Worktrees β β
|
|
379
|
+
β ββββββββββββββββββββββββββββ β
|
|
380
|
+
β β β
|
|
381
|
+
β βββββββββββββββββΌββββββββββββββββ β
|
|
382
|
+
β βΌ βΌ βΌ β
|
|
383
|
+
β ββββββββββββ ββββββββββββ ββββββββββββ β
|
|
384
|
+
β β Agent 1 β β Agent 2 β β Agent 3 β β
|
|
385
|
+
β β worktree β β worktree β β worktree β β
|
|
386
|
+
β β Task A β β Task B β β Task C β β
|
|
387
|
+
β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ β
|
|
388
|
+
β β β β β
|
|
389
|
+
β βΌ βΌ βΌ β
|
|
390
|
+
β branch-a branch-b branch-c β
|
|
391
|
+
β β β β β
|
|
392
|
+
β ββββββββββββββββΌβββββββββββββββ β
|
|
393
|
+
β βΌ β
|
|
394
|
+
β ββββββββββββββββ β
|
|
395
|
+
β β Auto-Merge β β
|
|
396
|
+
β β to base β β
|
|
397
|
+
β ββββββββββββββββ β
|
|
398
|
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**Key benefits:**
|
|
402
|
+
- Each agent works in complete isolation (separate git worktree)
|
|
403
|
+
- No interference between agents working on different tasks
|
|
404
|
+
- Branches auto-merge after completion (or keep separate with `--no-merge`)
|
|
405
|
+
- Conflict detection and reporting
|
|
406
|
+
- Tasks are processed in batches (e.g., 5 agents = 5 tasks per batch)
|
|
407
|
+
- In parallel mode, agents do **not** update `.ralph/progress.md` (they write per-agent reports instead)
|
|
408
|
+
|
|
409
|
+
**When to use parallel mode:**
|
|
410
|
+
- Multiple independent tasks that don't conflict
|
|
411
|
+
- Large task lists you want completed faster
|
|
412
|
+
- CI/CD pipelines with parallelization budget
|
|
413
|
+
|
|
414
|
+
**When to use sequential mode:**
|
|
415
|
+
- Tasks that depend on each other
|
|
416
|
+
- Single complex task that needs focused attention
|
|
417
|
+
- Limited API rate limits
|
|
418
|
+
|
|
419
|
+
### Recommended Workflow: Parallel + Integration Pass
|
|
420
|
+
|
|
421
|
+
For best results, structure your work in two phases:
|
|
422
|
+
|
|
423
|
+
**Phase 1: Parallel execution** (isolated, independent tasks)
|
|
424
|
+
```markdown
|
|
425
|
+
# Tasks
|
|
426
|
+
- [ ] Add user authentication to /api/auth
|
|
427
|
+
- [ ] Create dashboard component
|
|
428
|
+
- [ ] Implement data export feature
|
|
429
|
+
- [ ] Add unit tests for utils/
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Phase 2: Integration pass** (one sequential agent, repo-wide polish)
|
|
433
|
+
```markdown
|
|
434
|
+
# Tasks
|
|
435
|
+
- [ ] Update README with new features
|
|
436
|
+
- [ ] Bump version in package.json
|
|
437
|
+
- [ ] Update CHANGELOG
|
|
438
|
+
- [ ] Fix any integration issues from parallel work
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
This pattern maximizes parallelism while avoiding merge conflicts on shared files.
|
|
442
|
+
The integration pass runs after parallel agents finish and handles all "touch everything" work.
|
|
443
|
+
|
|
444
|
+
### Task Groups (Phased Execution)
|
|
445
|
+
|
|
446
|
+
Control execution order with `<!-- group: N -->` annotations:
|
|
447
|
+
|
|
448
|
+
```markdown
|
|
449
|
+
# Tasks
|
|
450
|
+
|
|
451
|
+
- [ ] Create database schema <!-- group: 1 -->
|
|
452
|
+
- [ ] Create User model <!-- group: 1 -->
|
|
453
|
+
- [ ] Create Post model <!-- group: 1 -->
|
|
454
|
+
- [ ] Add relationships between models <!-- group: 2 -->
|
|
455
|
+
- [ ] Build API endpoints <!-- group: 3 -->
|
|
456
|
+
- [ ] Update README # no annotation = runs LAST
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Execution order:**
|
|
460
|
+
1. Group 1 - runs first (all tasks in parallel, up to `--max-parallel`)
|
|
461
|
+
2. Group 2 - runs after group 1 merges complete
|
|
462
|
+
3. Group 3 - runs after group 2 merges complete
|
|
463
|
+
4. Unannotated tasks - run LAST (after all annotated groups)
|
|
464
|
+
|
|
465
|
+
**Why unannotated = last?**
|
|
466
|
+
- Safer default: forgetting to annotate doesn't jump the queue
|
|
467
|
+
- Integration/polish tasks naturally go last
|
|
468
|
+
- Override with `DEFAULT_GROUP=0` env var if you prefer unannotated first
|
|
469
|
+
|
|
470
|
+
**Within each group:**
|
|
471
|
+
- Tasks run in parallel (up to `--max-parallel`)
|
|
472
|
+
- All merges complete before next group starts
|
|
473
|
+
- RALPH_TASK.md checkboxes updated per group
|
|
474
|
+
|
|
475
|
+
**Worktree structure:**
|
|
476
|
+
```
|
|
477
|
+
project/
|
|
478
|
+
βββ .ralph-worktrees/ # Temporary worktrees (auto-cleaned)
|
|
479
|
+
β βββ <run_id>-job1/ # Agent worktree (isolated)
|
|
480
|
+
β βββ <run_id>-job2/ # Agent worktree (isolated)
|
|
481
|
+
β βββ <run_id>-job3/ # Agent worktree (isolated)
|
|
482
|
+
βββ (original project files)
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Worktrees are automatically cleaned up after agents complete. Failed agents preserve their worktree for manual inspection.
|
|
486
|
+
|
|
487
|
+
### Parallel logs & per-agent reports
|
|
488
|
+
|
|
489
|
+
Each parallel run creates a run directory:
|
|
490
|
+
|
|
491
|
+
```
|
|
492
|
+
.ralph/parallel/<run_id>/
|
|
493
|
+
βββ manifest.tsv # job_id -> task_id -> branch -> status -> log
|
|
494
|
+
βββ jobN.log # full cursor-agent output for that job
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Agents are instructed to write a committed per-agent report (to avoid `.ralph/progress.md` merge conflicts):
|
|
498
|
+
|
|
499
|
+
```
|
|
500
|
+
.ralph/parallel/<run_id>/agent-jobN.md
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
## How It Works
|
|
504
|
+
|
|
505
|
+
### The Loop
|
|
506
|
+
|
|
507
|
+
```
|
|
508
|
+
Iteration 1 Iteration 2 Iteration N
|
|
509
|
+
ββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ
|
|
510
|
+
β Fresh context β β Fresh context β β Fresh context β
|
|
511
|
+
β β β β β β β β β
|
|
512
|
+
β βΌ β β βΌ β β βΌ β
|
|
513
|
+
β Read RALPH_TASK β β Read RALPH_TASK β β Read RALPH_TASK β
|
|
514
|
+
β Read guardrails ββββββββββββ Read guardrails ββββββββββββ Read guardrails β
|
|
515
|
+
β Read progress β (state β Read progress β (state β Read progress β
|
|
516
|
+
β β β in git) β β β in git) β β β
|
|
517
|
+
β βΌ β β βΌ β β βΌ β
|
|
518
|
+
β Work on criteria β β Work on criteria β β Work on criteria β
|
|
519
|
+
β Commit to git β β Commit to git β β Commit to git β
|
|
520
|
+
β β β β β β β β β
|
|
521
|
+
β βΌ β β βΌ β β βΌ β
|
|
522
|
+
β 80k tokens β β 80k tokens β β All [x] done! β
|
|
523
|
+
β ROTATE βββββββββββΌβββββββββββΌβββββββββββββββββββΌβββββββββββΌβββΊ COMPLETE β
|
|
524
|
+
ββββββββββββββββββββ ββββββββββββββββββββ ββββββββββββββββββββ
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
Each iteration:
|
|
528
|
+
1. Reads task and state from files (not from previous context)
|
|
529
|
+
2. Works on unchecked criteria
|
|
530
|
+
3. Commits progress to git
|
|
531
|
+
4. Updates `.ralph/progress.md` and `.ralph/guardrails.md`
|
|
532
|
+
5. Rotates when context is full
|
|
533
|
+
|
|
534
|
+
### Git Protocol
|
|
535
|
+
|
|
536
|
+
The agent is instructed to commit frequently:
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
# After each criterion
|
|
540
|
+
git add -A && git commit -m 'ralph: [criterion] - description'
|
|
541
|
+
|
|
542
|
+
# Push periodically
|
|
543
|
+
git push
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
**Commits are the agent's memory.** The next iteration picks up from git history.
|
|
547
|
+
|
|
548
|
+
### The Learning Loop (Signs)
|
|
549
|
+
|
|
550
|
+
When something fails, the agent adds a "Sign" to `.ralph/guardrails.md`:
|
|
551
|
+
|
|
552
|
+
```markdown
|
|
553
|
+
### Sign: Check imports before adding
|
|
554
|
+
- **Trigger**: Adding a new import statement
|
|
555
|
+
- **Instruction**: First check if import already exists in file
|
|
556
|
+
- **Added after**: Iteration 3 - duplicate import caused build failure
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
Future iterations read guardrails first and follow them, preventing repeated mistakes.
|
|
560
|
+
|
|
561
|
+
```
|
|
562
|
+
Error occurs β errors.log β Agent analyzes β Updates guardrails.md β Future agents follow
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
## Context Health Indicators
|
|
566
|
+
|
|
567
|
+
The activity log shows context health with emoji:
|
|
568
|
+
|
|
569
|
+
| Emoji | Status | Token % | Meaning |
|
|
570
|
+
|-------|--------|---------|---------|
|
|
571
|
+
| π’ | Healthy | < 60% | Plenty of room |
|
|
572
|
+
| π‘ | Warning | 60-80% | Approaching limit |
|
|
573
|
+
| π΄ | Critical | > 80% | Rotation imminent |
|
|
574
|
+
|
|
575
|
+
Example:
|
|
576
|
+
```
|
|
577
|
+
[12:34:56] π’ READ src/index.ts (245 lines, ~24.5KB)
|
|
578
|
+
[12:40:22] π‘ TOKENS: 58,000 / 80,000 (72%) - approaching limit [read:40KB write:8KB assist:10KB shell:0KB]
|
|
579
|
+
[12:45:33] π΄ TOKENS: 72,500 / 80,000 (90%) - rotation imminent
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
## Gutter Detection
|
|
583
|
+
|
|
584
|
+
The parser detects when the agent is stuck:
|
|
585
|
+
|
|
586
|
+
| Pattern | Trigger | What Happens |
|
|
587
|
+
|---------|---------|--------------|
|
|
588
|
+
| Repeated failure | Same command failed 3x | GUTTER signal |
|
|
589
|
+
| File thrashing | Same file written 5x in 10 min | GUTTER signal |
|
|
590
|
+
| Agent signals | Agent outputs `<ralph>GUTTER</ralph>` | GUTTER signal |
|
|
591
|
+
|
|
592
|
+
When gutter is detected:
|
|
593
|
+
1. Check `.ralph/errors.log` for the pattern
|
|
594
|
+
2. Fix the issue manually or add a guardrail
|
|
595
|
+
3. Re-run the loop
|
|
596
|
+
|
|
597
|
+
## Rate Limit & Transient Error Handling
|
|
598
|
+
|
|
599
|
+
The parser detects retryable API errors and handles them gracefully:
|
|
600
|
+
|
|
601
|
+
| Error Type | Examples | What Happens |
|
|
602
|
+
|------------|----------|--------------|
|
|
603
|
+
| Rate limits | 429, "rate limit exceeded", "quota" | DEFER signal |
|
|
604
|
+
| Network errors | timeout, connection reset, ECONNRESET | DEFER signal |
|
|
605
|
+
| Server errors | 502, 503, 504, "service unavailable" | DEFER signal |
|
|
606
|
+
|
|
607
|
+
When DEFER is triggered:
|
|
608
|
+
1. Agent stops current iteration
|
|
609
|
+
2. Waits with **exponential backoff** (15s base, doubles each retry, max 120s)
|
|
610
|
+
3. Adds jitter (0-25%) to prevent thundering herd
|
|
611
|
+
4. Retries the same task (does not increment iteration)
|
|
612
|
+
|
|
613
|
+
Example log:
|
|
614
|
+
```
|
|
615
|
+
βΈοΈ Rate limit or transient error detected.
|
|
616
|
+
Waiting 32s before retrying (attempt 2)...
|
|
617
|
+
Resuming...
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
## Completion Detection
|
|
621
|
+
|
|
622
|
+
Ralph detects completion in two ways:
|
|
623
|
+
|
|
624
|
+
1. **Checkbox check**: All `[ ]` in RALPH_TASK.md changed to `[x]`
|
|
625
|
+
2. **Agent sigil**: Agent outputs `<ralph>COMPLETE</ralph>`
|
|
626
|
+
|
|
627
|
+
Both are verified before declaring success.
|
|
628
|
+
|
|
629
|
+
## File Reference
|
|
630
|
+
|
|
631
|
+
| File | Purpose | Who Uses It |
|
|
632
|
+
|------|---------|-------------|
|
|
633
|
+
| `RALPH_TASK.md` | Task definition + success criteria | You define, agent reads |
|
|
634
|
+
| `.ralph/progress.md` | What's been accomplished | Agent writes after work |
|
|
635
|
+
| `.ralph/guardrails.md` | Lessons learned (Signs) | Agent reads first, writes after failures |
|
|
636
|
+
| `.ralph/activity.log` | Tool call log with token counts | Parser writes, you monitor |
|
|
637
|
+
| `.ralph/errors.log` | Failures + gutter detection | Parser writes, agent reads |
|
|
638
|
+
| `.ralph/tasks.yaml` | Cached task state (auto-generated) | Task parser writes/reads |
|
|
639
|
+
| `.ralph/tasks.mtime` | Task file modification time | Cache invalidation |
|
|
640
|
+
| `.ralph/.iteration` | Current iteration number | Parser reads/writes |
|
|
641
|
+
|
|
642
|
+
## Configuration
|
|
643
|
+
|
|
644
|
+
Configuration is set via command-line flags or environment variables:
|
|
645
|
+
|
|
646
|
+
```bash
|
|
647
|
+
# Via flags (recommended)
|
|
648
|
+
ralph-cursor loop -n 50 -m gpt-5.2-high
|
|
649
|
+
|
|
650
|
+
# Via environment
|
|
651
|
+
RALPH_MODEL=gpt-5.2-high MAX_ITERATIONS=50 ralph-cursor loop
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
Default thresholds (config or env):
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
MAX_ITERATIONS=20 # Max rotations before giving up
|
|
658
|
+
WARN_THRESHOLD=70000 # Tokens: send wrapup warning
|
|
659
|
+
ROTATE_THRESHOLD=80000 # Tokens: force rotation
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
## Troubleshooting
|
|
663
|
+
|
|
664
|
+
### "cursor-agent CLI not found"
|
|
665
|
+
|
|
666
|
+
```bash
|
|
667
|
+
curl https://cursor.com/install -fsS | bash
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Agent keeps failing on same thing
|
|
671
|
+
|
|
672
|
+
Check `.ralph/errors.log` for the pattern. Either:
|
|
673
|
+
1. Fix the underlying issue manually
|
|
674
|
+
2. Add a guardrail to `.ralph/guardrails.md` explaining what to do differently
|
|
675
|
+
|
|
676
|
+
### Context rotates too frequently
|
|
677
|
+
|
|
678
|
+
The agent might be reading too many large files. Check `activity.log` for large READs and consider:
|
|
679
|
+
1. Adding a guardrail: "Don't read the entire file, use grep to find relevant sections"
|
|
680
|
+
2. Breaking the task into smaller pieces
|
|
681
|
+
|
|
682
|
+
### Task never completes
|
|
683
|
+
|
|
684
|
+
Check if criteria are too vague. Each criterion should be:
|
|
685
|
+
- Specific and testable
|
|
686
|
+
- Achievable in a single iteration
|
|
687
|
+
- Not dependent on manual steps
|
|
688
|
+
|
|
689
|
+
## Workflows
|
|
690
|
+
|
|
691
|
+
### Basic (default)
|
|
692
|
+
|
|
693
|
+
```bash
|
|
694
|
+
ralph-cursor run # Interactive setup β runs loop β done
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Human-in-the-loop (recommended for new tasks)
|
|
698
|
+
|
|
699
|
+
```bash
|
|
700
|
+
ralph-cursor once # Run ONE iteration
|
|
701
|
+
# Review changes...
|
|
702
|
+
ralph-cursor run # Continue with full loop
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
### Scripted/CI
|
|
706
|
+
|
|
707
|
+
```bash
|
|
708
|
+
ralph-cursor loop --branch feature/foo --pr -y
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
## Learn More
|
|
712
|
+
|
|
713
|
+
- [Original Ralph technique](https://ghuntley.com/ralph/) - Geoffrey Huntley
|
|
714
|
+
- [Context as memory](https://ghuntley.com/allocations/) - The malloc/free metaphor
|
|
715
|
+
- [Cursor CLI docs](https://cursor.com/docs/cli/headless)
|
|
716
|
+
|
|
717
|
+
## Credits
|
|
718
|
+
|
|
719
|
+
- **Original technique**: [Geoffrey Huntley](https://ghuntley.com/ralph/) - the Ralph Wiggum methodology
|
|
720
|
+
- **Cursor port**: [Agrim Singh](https://x.com/agrimsingh) - this implementation
|
|
721
|
+
|
|
722
|
+
## License
|
|
723
|
+
|
|
724
|
+
MIT
|