Skip to content

Commit e87eaec

Browse files
Add Ralph Loop plugin (#15)
* Add Ralph Loop plugin Port of the Ralph Wiggum technique from Claude Code to Cursor. Runs Cursor in a self-referential loop, feeding the same prompt back after every turn until a completion condition is met. Components: - Stop hook that intercepts session exit and re-injects the prompt - Setup script for initializing loop state - Skills for starting, cancelling, and explaining the loop Co-authored-by: Cursor <cursoragent@cursor.com> * Comply with Cursor hooks API - Rewrite hooks.json to Cursor format (version 1, lowercase event names, flat structure, loop_limit: null) - Replace Claude Code stop hook output (decision/block/reason) with Cursor's followup_message API - Add afterAgentResponse hook to detect completion promise without depending on transcript format - Use CURSOR_PROJECT_DIR env var for reliable state file paths - Remove setup script; ralph-loop skill now instructs the agent to create the state file directly - Update cancel-ralph skill to clean up done flag file Co-authored-by: Cursor <cursoragent@cursor.com> * Move state files to .cursor/ralph/ subdirectory State file: .cursor/ralph/scratchpad.md Done flag: .cursor/ralph/done Cancel cleans up with rm -rf .cursor/ralph Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 837194d commit e87eaec

File tree

11 files changed

+428
-0
lines changed

11 files changed

+428
-0
lines changed

.cursor-plugin/marketplace.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@
7272
"name": "figma",
7373
"source": "figma",
7474
"description": "Figma MCP integration for design and collaboration."
75+
},
76+
{
77+
"name": "ralph-loop",
78+
"source": "ralph-loop",
79+
"description": "Iterative self-referential AI loops using the Ralph Wiggum technique."
7580
}
7681
]
7782
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Official Cursor plugins for popular developer tools, frameworks, and SaaS produc
1818
| [Learning](learning/) | Utilities | Skill maps, practice plans, and feedback loops |
1919
| [Cursor Dev Kit](cursor-dev-kit/) | Developer Tools | Internal-style workflows for CI, code review, shipping, and testing |
2020
| [Create Plugin](create-plugin/) | Developer Tools | Meta workflows for creating Cursor plugins with scaffolding and submission checks |
21+
| [Ralph Loop](ralph-loop/) | Developer Tools | Iterative self-referential AI loops using the Ralph Wiggum technique |
2122

2223
## Repository structure
2324

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "ralph-loop",
3+
"displayName": "Ralph Loop",
4+
"version": "1.0.0",
5+
"description": "Continuous self-referential AI loops for iterative development, implementing the Ralph Wiggum technique. Run the agent in a while-true loop with the same prompt until task completion.",
6+
"author": {
7+
"name": "Cursor",
8+
"email": "plugins@cursor.com"
9+
},
10+
"homepage": "https://github.com/cursor/plugins",
11+
"repository": "https://github.com/cursor/plugins",
12+
"license": "MIT",
13+
"keywords": [
14+
"ralph",
15+
"loop",
16+
"iteration",
17+
"self-referential",
18+
"automation",
19+
"iterative-development"
20+
],
21+
"category": "developer-tools",
22+
"tags": [
23+
"automation",
24+
"iteration",
25+
"agent-loop"
26+
],
27+
"skills": "./skills/",
28+
"hooks": "./hooks/hooks.json"
29+
}

ralph-loop/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Cursor
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

ralph-loop/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Ralph Loop
2+
3+
Ralph Loop runs Cursor in a self-referential loop, feeding the same prompt back after every turn until the task is complete. It implements the [Ralph Wiggum technique](https://ghuntley.com/ralph/) pioneered by Geoffrey Huntley.
4+
5+
## How it works
6+
7+
Two hooks drive the loop. An `afterAgentResponse` hook watches each response for a `<promise>` tag matching the completion phrase. A `stop` hook fires when Cursor finishes a turn. If the promise hasn't been detected and the iteration limit hasn't been reached, the stop hook sends the original prompt back as a `followup_message`, starting the next iteration. Cursor sees its own previous edits in the working tree and git history, iterates on them, and repeats. The prompt never changes. The code does.
8+
9+
## Installation
10+
11+
```
12+
agent install ralph-loop
13+
```
14+
15+
## Quick start
16+
17+
> Start a ralph loop: "Build a REST API for todos. CRUD operations, input validation, tests. Output COMPLETE when done." --completion-promise "COMPLETE" --max-iterations 50
18+
19+
Cursor will implement the API, run tests, see failures, fix them, and repeat until all requirements are met.
20+
21+
## Skills
22+
23+
**ralph-loop** starts the loop. Provide a prompt and options:
24+
25+
> Start a ralph loop: "Refactor the cache layer" --max-iterations 20 --completion-promise "DONE"
26+
27+
- `--max-iterations <N>` stops after N iterations (default: unlimited)
28+
- `--completion-promise <text>` sets the phrase that signals completion
29+
30+
**cancel-ralph** removes the state file and stops the loop.
31+
32+
**ralph-loop-help** explains the technique and usage in detail.
33+
34+
## Writing good prompts
35+
36+
Define explicit completion criteria. Vague goals like "make it good" give Cursor nothing to verify against.
37+
38+
```markdown
39+
Build a REST API for todos.
40+
41+
When complete:
42+
- All CRUD endpoints working
43+
- Input validation in place
44+
- Tests passing (coverage > 80%)
45+
- Output: <promise>COMPLETE</promise>
46+
```
47+
48+
Break large tasks into phases. Encourage self-correction by including test/fix cycles in the prompt. Always pass `--max-iterations` to prevent runaway loops.
49+
50+
## When to use Ralph Loop
51+
52+
Works well for tasks with clear, verifiable success criteria: getting tests to pass, completing a migration, building a feature from a spec. Not a good fit for tasks that need human judgment or have ambiguous goals.
53+
54+
## Learn more
55+
56+
- [Original technique by Geoffrey Huntley](https://ghuntley.com/ralph/)
57+
- [Ralph Orchestrator](https://github.com/mikeyobrien/ralph-orchestrator)
58+
59+
## License
60+
61+
MIT
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/bin/bash
2+
3+
# afterAgentResponse hook for Ralph Loop.
4+
# Checks if the agent's response contains a matching completion promise.
5+
# If found, writes a done flag so the stop hook knows to end the loop.
6+
#
7+
# Input: { "text": "<assistant response text>" }
8+
# Output: none (fire-and-forget)
9+
10+
set -euo pipefail
11+
12+
HOOK_INPUT=$(cat)
13+
14+
PROJECT_DIR="${CURSOR_PROJECT_DIR:-.}"
15+
STATE_FILE="$PROJECT_DIR/.cursor/ralph/scratchpad.md"
16+
DONE_FLAG="$PROJECT_DIR/.cursor/ralph/done"
17+
18+
# No active loop, nothing to do
19+
if [[ ! -f "$STATE_FILE" ]]; then
20+
exit 0
21+
fi
22+
23+
# Extract completion promise from state file frontmatter
24+
FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$STATE_FILE")
25+
COMPLETION_PROMISE=$(echo "$FRONTMATTER" | grep '^completion_promise:' | sed 's/completion_promise: *//' | sed 's/^"\(.*\)"$/\1/')
26+
27+
# No promise configured, nothing to check
28+
if [[ "$COMPLETION_PROMISE" = "null" ]] || [[ -z "$COMPLETION_PROMISE" ]]; then
29+
exit 0
30+
fi
31+
32+
# Extract response text from hook input
33+
RESPONSE_TEXT=$(echo "$HOOK_INPUT" | jq -r '.text // empty')
34+
35+
if [[ -z "$RESPONSE_TEXT" ]]; then
36+
exit 0
37+
fi
38+
39+
# Check for <promise>TEXT</promise> in the response
40+
PROMISE_TEXT=$(echo "$RESPONSE_TEXT" | perl -0777 -pe 's/.*?<promise>(.*?)<\/promise>.*/$1/s; s/^\s+|\s+$//g; s/\s+/ /g' 2>/dev/null || echo "")
41+
42+
if [[ -n "$PROMISE_TEXT" ]] && [[ "$PROMISE_TEXT" = "$COMPLETION_PROMISE" ]]; then
43+
touch "$DONE_FLAG"
44+
fi
45+
46+
exit 0

ralph-loop/hooks/hooks.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"version": 1,
3+
"hooks": {
4+
"afterAgentResponse": [
5+
{
6+
"command": "./hooks/capture-response.sh"
7+
}
8+
],
9+
"stop": [
10+
{
11+
"command": "./hooks/stop-hook.sh",
12+
"loop_limit": null
13+
}
14+
]
15+
}
16+
}

ralph-loop/hooks/stop-hook.sh

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/bin/bash
2+
3+
# Ralph Loop stop hook.
4+
# When the agent finishes a turn, this hook decides whether to feed the
5+
# same prompt back for another iteration or let the session end.
6+
#
7+
# Cursor stop hook API:
8+
# Input: { "status": "completed"|"aborted"|"error", "loop_count": N, ...common }
9+
# Output: { "followup_message": "<text>" } to continue, or exit 0 with no output to stop
10+
11+
set -euo pipefail
12+
13+
HOOK_INPUT=$(cat)
14+
15+
PROJECT_DIR="${CURSOR_PROJECT_DIR:-.}"
16+
STATE_FILE="$PROJECT_DIR/.cursor/ralph/scratchpad.md"
17+
DONE_FLAG="$PROJECT_DIR/.cursor/ralph/done"
18+
19+
# No active loop. Let the session end.
20+
if [[ ! -f "$STATE_FILE" ]]; then
21+
exit 0
22+
fi
23+
24+
# Parse state file frontmatter
25+
FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$STATE_FILE")
26+
ITERATION=$(echo "$FRONTMATTER" | grep '^iteration:' | sed 's/iteration: *//')
27+
MAX_ITERATIONS=$(echo "$FRONTMATTER" | grep '^max_iterations:' | sed 's/max_iterations: *//')
28+
COMPLETION_PROMISE=$(echo "$FRONTMATTER" | grep '^completion_promise:' | sed 's/completion_promise: *//' | sed 's/^"\(.*\)"$/\1/')
29+
30+
# Validate iteration is numeric
31+
if [[ ! "$ITERATION" =~ ^[0-9]+$ ]]; then
32+
echo "Ralph loop: state file corrupted (iteration: '$ITERATION'). Stopping." >&2
33+
rm -f "$STATE_FILE" "$DONE_FLAG"
34+
exit 0
35+
fi
36+
37+
if [[ ! "$MAX_ITERATIONS" =~ ^[0-9]+$ ]]; then
38+
echo "Ralph loop: state file corrupted (max_iterations: '$MAX_ITERATIONS'). Stopping." >&2
39+
rm -f "$STATE_FILE" "$DONE_FLAG"
40+
exit 0
41+
fi
42+
43+
# Check if completion promise was detected by the afterAgentResponse hook
44+
if [[ -f "$DONE_FLAG" ]]; then
45+
echo "Ralph loop: completion promise fulfilled at iteration $ITERATION." >&2
46+
rm -f "$STATE_FILE" "$DONE_FLAG"
47+
exit 0
48+
fi
49+
50+
# Check max iterations
51+
if [[ $MAX_ITERATIONS -gt 0 ]] && [[ $ITERATION -ge $MAX_ITERATIONS ]]; then
52+
echo "Ralph loop: max iterations ($MAX_ITERATIONS) reached." >&2
53+
rm -f "$STATE_FILE" "$DONE_FLAG"
54+
exit 0
55+
fi
56+
57+
# Extract prompt text (everything after the closing --- in frontmatter)
58+
PROMPT_TEXT=$(awk '/^---$/{i++; next} i>=2' "$STATE_FILE")
59+
60+
if [[ -z "$PROMPT_TEXT" ]]; then
61+
echo "Ralph loop: no prompt text found in state file. Stopping." >&2
62+
rm -f "$STATE_FILE" "$DONE_FLAG"
63+
exit 0
64+
fi
65+
66+
# Increment iteration
67+
NEXT_ITERATION=$((ITERATION + 1))
68+
TEMP_FILE="${STATE_FILE}.tmp.$$"
69+
sed "s/^iteration: .*/iteration: $NEXT_ITERATION/" "$STATE_FILE" > "$TEMP_FILE"
70+
mv "$TEMP_FILE" "$STATE_FILE"
71+
72+
# Build the followup message: iteration context + original prompt
73+
if [[ "$COMPLETION_PROMISE" != "null" ]] && [[ -n "$COMPLETION_PROMISE" ]]; then
74+
HEADER="[Ralph loop iteration $NEXT_ITERATION. To complete: output <promise>$COMPLETION_PROMISE</promise> ONLY when genuinely true.]"
75+
else
76+
HEADER="[Ralph loop iteration $NEXT_ITERATION.]"
77+
fi
78+
79+
FOLLOWUP="$HEADER
80+
81+
$PROMPT_TEXT"
82+
83+
# Output followup_message to continue the loop
84+
jq -n --arg msg "$FOLLOWUP" '{"followup_message": $msg}'
85+
86+
exit 0
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
name: cancel-ralph
3+
description: Cancel an active Ralph Loop. Use when the user wants to stop, cancel, or abort a running ralph loop.
4+
---
5+
6+
# Cancel Ralph
7+
8+
## Trigger
9+
10+
The user wants to cancel or stop an active Ralph loop.
11+
12+
## Workflow
13+
14+
1. Check if `.cursor/ralph/scratchpad.md` exists.
15+
16+
2. **If it does not exist**: Tell the user "No active Ralph loop found."
17+
18+
3. **If it exists**:
19+
- Read `.cursor/ralph/scratchpad.md` to get the current iteration from the `iteration:` field.
20+
- Remove the state file and any done flag:
21+
```bash
22+
rm -rf .cursor/ralph
23+
```
24+
- Report: "Cancelled Ralph loop (was at iteration N)."
25+
26+
## Output
27+
28+
A short confirmation with the iteration count, or a message that no loop was active.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
name: ralph-loop-help
3+
description: Explain the Ralph Loop plugin, how it works, and available skills. Use when the user asks for help with ralph loop, wants to understand the technique, or needs usage examples.
4+
---
5+
6+
# Ralph Loop Help
7+
8+
## Trigger
9+
10+
The user asks what Ralph Loop is, how it works, or needs usage guidance.
11+
12+
## What to Explain
13+
14+
### What is Ralph Loop?
15+
16+
Ralph Loop implements the Ralph Wiggum technique — an iterative development methodology based on continuous AI loops, pioneered by Geoffrey Huntley.
17+
18+
Core concept: the same prompt is fed to the agent repeatedly. The "self-referential" aspect comes from the agent seeing its own previous work in the files and git history, not from feeding output back as input.
19+
20+
Each iteration:
21+
1. The agent receives the SAME prompt
22+
2. Works on the task, modifying files
23+
3. Tries to exit
24+
4. Stop hook intercepts and feeds the same prompt again
25+
5. The agent sees its previous work in the files
26+
6. Iteratively improves until completion
27+
28+
### Starting a Ralph Loop
29+
30+
Tell the agent your task along with options:
31+
32+
```
33+
Start a ralph loop: "Build a REST API for todos" --max-iterations 20 --completion-promise "COMPLETE"
34+
```
35+
36+
Options:
37+
- `--max-iterations N` — max iterations before auto-stop
38+
- `--completion-promise "TEXT"` — phrase to signal completion
39+
40+
How it works:
41+
1. Creates `.cursor/ralph/scratchpad.md` state file
42+
2. Agent works on the task
43+
3. Stop hook intercepts exit and feeds the same prompt back
44+
4. Agent sees its previous work and iterates
45+
5. Continues until promise detected or max iterations reached
46+
47+
### Cancelling a Ralph Loop
48+
49+
Ask the agent to cancel the ralph loop. It will remove the state file and report the iteration count.
50+
51+
### Completion Promises
52+
53+
To signal completion, the agent outputs a `<promise>` tag:
54+
55+
```
56+
<promise>TASK COMPLETE</promise>
57+
```
58+
59+
The stop hook looks for this specific tag. Without it (or `--max-iterations`), Ralph runs indefinitely.
60+
61+
### When to Use Ralph
62+
63+
**Good for:**
64+
- Well-defined tasks with clear success criteria
65+
- Tasks requiring iteration and refinement
66+
- Iterative development with self-correction
67+
- Greenfield projects
68+
69+
**Not good for:**
70+
- Tasks requiring human judgment or design decisions
71+
- One-shot operations
72+
- Tasks with unclear success criteria
73+
74+
### Learn More
75+
76+
- Original technique: https://ghuntley.com/ralph/
77+
- Ralph Orchestrator: https://github.com/mikeyobrien/ralph-orchestrator
78+
79+
## Output
80+
81+
Present the above information clearly to the user, tailored to their specific question.

0 commit comments

Comments
 (0)