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.
Files changed (94) hide show
  1. package/README.md +724 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +60 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/doctor.d.ts +3 -0
  7. package/dist/commands/doctor.d.ts.map +1 -0
  8. package/dist/commands/doctor.js +69 -0
  9. package/dist/commands/doctor.js.map +1 -0
  10. package/dist/commands/init.d.ts +3 -0
  11. package/dist/commands/init.d.ts.map +1 -0
  12. package/dist/commands/init.js +162 -0
  13. package/dist/commands/init.js.map +1 -0
  14. package/dist/commands/logs.d.ts +3 -0
  15. package/dist/commands/logs.d.ts.map +1 -0
  16. package/dist/commands/logs.js +28 -0
  17. package/dist/commands/logs.js.map +1 -0
  18. package/dist/commands/loop.d.ts +3 -0
  19. package/dist/commands/loop.d.ts.map +1 -0
  20. package/dist/commands/loop.js +186 -0
  21. package/dist/commands/loop.js.map +1 -0
  22. package/dist/commands/once.d.ts +3 -0
  23. package/dist/commands/once.d.ts.map +1 -0
  24. package/dist/commands/once.js +187 -0
  25. package/dist/commands/once.js.map +1 -0
  26. package/dist/commands/run.d.ts +3 -0
  27. package/dist/commands/run.d.ts.map +1 -0
  28. package/dist/commands/run.js +328 -0
  29. package/dist/commands/run.js.map +1 -0
  30. package/dist/commands/status.d.ts +3 -0
  31. package/dist/commands/status.d.ts.map +1 -0
  32. package/dist/commands/status.js +33 -0
  33. package/dist/commands/status.js.map +1 -0
  34. package/dist/commands/task.d.ts +3 -0
  35. package/dist/commands/task.d.ts.map +1 -0
  36. package/dist/commands/task.js +161 -0
  37. package/dist/commands/task.js.map +1 -0
  38. package/dist/lib/config.d.ts +8 -0
  39. package/dist/lib/config.d.ts.map +1 -0
  40. package/dist/lib/config.js +48 -0
  41. package/dist/lib/config.js.map +1 -0
  42. package/dist/lib/last-run.d.ts +12 -0
  43. package/dist/lib/last-run.d.ts.map +1 -0
  44. package/dist/lib/last-run.js +33 -0
  45. package/dist/lib/last-run.js.map +1 -0
  46. package/dist/lib/ralph-dir.d.ts +6 -0
  47. package/dist/lib/ralph-dir.d.ts.map +1 -0
  48. package/dist/lib/ralph-dir.js +96 -0
  49. package/dist/lib/ralph-dir.js.map +1 -0
  50. package/dist/lib/spawn.d.ts +11 -0
  51. package/dist/lib/spawn.d.ts.map +1 -0
  52. package/dist/lib/spawn.js +29 -0
  53. package/dist/lib/spawn.js.map +1 -0
  54. package/dist/lib/tail.d.ts +9 -0
  55. package/dist/lib/tail.d.ts.map +1 -0
  56. package/dist/lib/tail.js +58 -0
  57. package/dist/lib/tail.js.map +1 -0
  58. package/dist/loop/index.d.ts +32 -0
  59. package/dist/loop/index.d.ts.map +1 -0
  60. package/dist/loop/index.js +165 -0
  61. package/dist/loop/index.js.map +1 -0
  62. package/dist/loop/prompt.d.ts +5 -0
  63. package/dist/loop/prompt.d.ts.map +1 -0
  64. package/dist/loop/prompt.js +77 -0
  65. package/dist/loop/prompt.js.map +1 -0
  66. package/dist/loop/retry.d.ts +22 -0
  67. package/dist/loop/retry.d.ts.map +1 -0
  68. package/dist/loop/retry.js +65 -0
  69. package/dist/loop/retry.js.map +1 -0
  70. package/dist/parallel/lock.d.ts +7 -0
  71. package/dist/parallel/lock.d.ts.map +1 -0
  72. package/dist/parallel/lock.js +110 -0
  73. package/dist/parallel/lock.js.map +1 -0
  74. package/dist/parallel/merge.d.ts +5 -0
  75. package/dist/parallel/merge.d.ts.map +1 -0
  76. package/dist/parallel/merge.js +39 -0
  77. package/dist/parallel/merge.js.map +1 -0
  78. package/dist/parallel/run.d.ts +18 -0
  79. package/dist/parallel/run.d.ts.map +1 -0
  80. package/dist/parallel/run.js +407 -0
  81. package/dist/parallel/run.js.map +1 -0
  82. package/dist/parallel/worktree.d.ts +12 -0
  83. package/dist/parallel/worktree.d.ts.map +1 -0
  84. package/dist/parallel/worktree.js +69 -0
  85. package/dist/parallel/worktree.js.map +1 -0
  86. package/dist/stream-parser/index.d.ts +18 -0
  87. package/dist/stream-parser/index.d.ts.map +1 -0
  88. package/dist/stream-parser/index.js +248 -0
  89. package/dist/stream-parser/index.js.map +1 -0
  90. package/dist/task-parser/index.d.ts +21 -0
  91. package/dist/task-parser/index.d.ts.map +1 -0
  92. package/dist/task-parser/index.js +195 -0
  93. package/dist/task-parser/index.js.map +1 -0
  94. 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