@lnilluv/pi-ralph-loop 1.2.0 → 1.3.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
CHANGED
|
@@ -1,25 +1,108 @@
|
|
|
1
|
-
# pi-ralph
|
|
2
|
-
Autonomous coding loops for pi with task folders, editable drafts, durable state, and per-iteration supervision.
|
|
1
|
+
# pi-ralph-loop
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
Autonomous coding loops for [pi](https://github.com/mariozechner/pi-coding-agent).
|
|
4
|
+
|
|
5
|
+
Describe what you want done. The loop runs your agent, re-reads the task, feeds fresh command output every iteration, and stops when the work is finished — or when you tell it to stop.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
/ralph "fix the flaky auth tests"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Why loops
|
|
12
|
+
|
|
13
|
+
A single agent run can fix a bug. But the real leverage is **sustained, autonomous work** — campaigns that run for hours, making progress one commit at a time while you do something else.
|
|
14
|
+
|
|
15
|
+
| Without a loop | With a loop |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Run an agent once, hope it finishes | Re-run until the work is done |
|
|
18
|
+
| Copy-paste test output back into chat | Commands feed fresh evidence each iteration |
|
|
19
|
+
| Watch the terminal and Ctrl+C when bored | Completion gating stops when the goal is met |
|
|
20
|
+
| One long context that gets stale | Fresh context every iteration |
|
|
21
|
+
| No guardrails — agent can push to main or delete secrets | Block commands, protect files, confine paths |
|
|
22
|
+
|
|
23
|
+
People use ralph loops for:
|
|
24
|
+
|
|
25
|
+
| Task | How the loop helps |
|
|
26
|
+
|---|---|
|
|
27
|
+
| Grow test coverage | Run the suite each iteration, only commit when coverage increases |
|
|
28
|
+
| Fix flaky tests | Run tests, find failures, fix, verify, repeat |
|
|
29
|
+
| Migrate a codebase | Transform one module per iteration, keep the build green |
|
|
30
|
+
| Write documentation | Check for doc build warnings, fix them, commit |
|
|
31
|
+
| Security audit | Scan for vulnerabilities, fix them, verify |
|
|
32
|
+
| Deep research | Write findings to files, iterate until the report is complete |
|
|
10
33
|
|
|
11
34
|
## Install
|
|
35
|
+
|
|
12
36
|
```bash
|
|
13
37
|
pi install npm:@lnilluv/pi-ralph-loop
|
|
14
38
|
```
|
|
15
39
|
|
|
16
40
|
## Quick start
|
|
17
|
-
1. Create `work/RALPH.md`.
|
|
18
|
-
2. Run `/ralph --path work --arg owner="Ada Lovelace"`.
|
|
19
|
-
3. If you want a draft first, use `/ralph-draft fix flaky auth tests`.
|
|
20
41
|
|
|
21
|
-
|
|
22
|
-
|
|
42
|
+
### From plain language
|
|
43
|
+
|
|
44
|
+
Draft and run in one command:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
/ralph "fix the failing auth tests"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The extension creates a `RALPH.md` draft and shows it for review. Edit, start, or cancel.
|
|
51
|
+
|
|
52
|
+
### With an existing task folder
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
/ralph --path ./my-task --arg owner="Ada"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### From a scaffold
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
/ralph-scaffold my-task
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Creates `my-task/RALPH.md` with a starter template — edit it, then run with `/ralph --path my-task`.
|
|
65
|
+
|
|
66
|
+
### What a run looks like
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
▶ Ralph loop started: my-task (max 20 iterations)
|
|
70
|
+
|
|
71
|
+
── Iteration 1 ──
|
|
72
|
+
Commands: 2 ran (tests, verify)
|
|
73
|
+
✗ auth/login.test.ts — 2 failures
|
|
74
|
+
✓ Iteration 1 completed (48.2s)
|
|
75
|
+
|
|
76
|
+
── Iteration 2 ──
|
|
77
|
+
Commands: 2 ran
|
|
78
|
+
✓ All tests passing
|
|
79
|
+
✓ Iteration 2 completed (23.1s)
|
|
80
|
+
|
|
81
|
+
Ralph loop complete: completion promise matched on iteration 2 (71s total)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## The task folder
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
my-task/
|
|
88
|
+
├── RALPH.md ← the prompt (required)
|
|
89
|
+
├── check-coverage.sh ← helper script (optional)
|
|
90
|
+
├── testing-conventions.md ← reference doc (optional)
|
|
91
|
+
├── RALPH_PROGRESS.md ← rolling memory (auto-managed)
|
|
92
|
+
└── .ralph-runner/ ← run state (auto-managed)
|
|
93
|
+
├── status.json
|
|
94
|
+
├── iterations.jsonl
|
|
95
|
+
├── events.jsonl
|
|
96
|
+
└── transcripts/
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Put scripts, reference docs, and data files alongside `RALPH.md`. The agent can read them every iteration. `RALPH_PROGRESS.md` is injected as rolling memory — the loop reads and writes it between iterations.
|
|
100
|
+
|
|
101
|
+
## RALPH.md format
|
|
102
|
+
|
|
103
|
+
YAML header (configuration) + Markdown body (the prompt). The header uses `snake_case` keys.
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
23
106
|
---
|
|
24
107
|
args:
|
|
25
108
|
- owner
|
|
@@ -30,52 +113,276 @@ commands:
|
|
|
30
113
|
- name: verify
|
|
31
114
|
run: ./scripts/verify.sh
|
|
32
115
|
timeout: 60
|
|
33
|
-
max_iterations:
|
|
34
|
-
timeout:
|
|
116
|
+
max_iterations: 20
|
|
117
|
+
timeout: 120
|
|
35
118
|
completion_promise: DONE
|
|
119
|
+
required_outputs:
|
|
120
|
+
- AUTH_FIXES.md
|
|
121
|
+
stop_on_error: false
|
|
122
|
+
guardrails:
|
|
123
|
+
block_commands:
|
|
124
|
+
- 'git\s+push'
|
|
125
|
+
protected_files:
|
|
126
|
+
- '.env*'
|
|
127
|
+
- 'policy:secret-bearing-paths'
|
|
36
128
|
---
|
|
129
|
+
|
|
37
130
|
Fix the failing auth tests for {{ args.owner }}.
|
|
38
131
|
|
|
39
|
-
|
|
40
|
-
|
|
132
|
+
## Current test results
|
|
133
|
+
|
|
134
|
+
{{ commands.tests }}
|
|
135
|
+
|
|
136
|
+
## Verification
|
|
137
|
+
|
|
138
|
+
{{ commands.verify }}
|
|
139
|
+
|
|
140
|
+
Stop with <promise>DONE</promise> only when all tests pass and AUTH_FIXES.md exists.
|
|
41
141
|
```
|
|
42
142
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
143
|
+
### Frontmatter reference
|
|
144
|
+
|
|
145
|
+
| YAML key | Type | Default | Description |
|
|
146
|
+
|---|---|---|---|
|
|
147
|
+
| `commands` | CommandDef[] | `[]` | Shell commands run each iteration. Each: `name`, `run`, `timeout` (1–300s, default 60) |
|
|
148
|
+
| `args` | string[] | `[]` | Declared runtime parameters for `--arg name=value` |
|
|
149
|
+
| `max_iterations` | integer | `50` | 1–50 |
|
|
150
|
+
| `inter_iteration_delay` | integer | `0` | Seconds between iterations |
|
|
151
|
+
| `timeout` | integer | `300` | 1–300 seconds per iteration |
|
|
152
|
+
| `completion_promise` | string | — | Done marker. Single line, no `<>` or line breaks |
|
|
153
|
+
| `required_outputs` | string[] | `[]` | Relative file paths that must exist for early stop |
|
|
154
|
+
| `stop_on_error` | boolean | `true` | `false` continues past RPC errors and timeouts |
|
|
155
|
+
| `guardrails.block_commands` | string[] | `[]` | Regex patterns; matching bash commands are blocked |
|
|
156
|
+
| `guardrails.protected_files` | string[] | `[]` | Glob patterns + `policy:secret-bearing-paths` |
|
|
157
|
+
|
|
158
|
+
### Body placeholders
|
|
159
|
+
|
|
160
|
+
| Placeholder | Resolves to |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `{{ commands.NAME }}` | Output of the named command |
|
|
163
|
+
| `{{ args.NAME }}` | Value of the named runtime arg |
|
|
164
|
+
| `{{ ralph.iteration }}` | Current iteration number |
|
|
165
|
+
| `{{ ralph.name }}` | Task directory basename |
|
|
166
|
+
| `{{ ralph.max_iterations }}` | Current max iterations |
|
|
167
|
+
|
|
168
|
+
Commands starting with `./` run from the task directory. Others run from the project root. Blocked commands produce `[blocked by guardrail: PATTERN]`. Timed-out commands produce `[timed out after Ns]`.
|
|
53
169
|
|
|
54
170
|
## Commands
|
|
55
|
-
|
|
171
|
+
|
|
172
|
+
| Command | What it does |
|
|
173
|
+
|---|---|
|
|
174
|
+
| `/ralph [path-or-task]` | Start or draft+start a loop |
|
|
175
|
+
| `/ralph-draft [path-or-task]` | Create or edit a draft without starting |
|
|
176
|
+
| `/ralph-stop [path-or-task]` | Finish current iteration, then stop |
|
|
177
|
+
| `/ralph-cancel [path-or-task]` | Kill the current iteration immediately |
|
|
178
|
+
| `/ralph-scaffold <name-or-path>` | Create a starter `RALPH.md` template |
|
|
179
|
+
| `/ralph-logs [--path] [--dest]` | Export run artifacts to a directory |
|
|
180
|
+
|
|
181
|
+
### Argument passing
|
|
182
|
+
|
|
183
|
+
`--arg name=value` is only valid with `--path` to an existing `RALPH.md`:
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
/ralph --path ./my-task --arg owner="Ada" --arg env=staging
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`/ralph-draft`, `/ralph-stop`, and `/ralph-cancel` reject `--arg`. Names must match `^\w[\w-]*$` and be declared in `args`.
|
|
190
|
+
|
|
191
|
+
### Stopping
|
|
192
|
+
|
|
193
|
+
| Action | Behavior |
|
|
194
|
+
|---|---|
|
|
195
|
+
| `/ralph-stop` | Finish current iteration, then stop |
|
|
196
|
+
| `/ralph-cancel` | Kill the current iteration immediately |
|
|
197
|
+
| Completion promise + gate | Stop when `<promise>DONE</promise>` appears and all `required_outputs` exist |
|
|
198
|
+
| Max iterations reached | Stop after the last iteration |
|
|
199
|
+
| No progress for all iterations | Stop with `no-progress-exhaustion` |
|
|
200
|
+
|
|
201
|
+
## Completion gating
|
|
202
|
+
|
|
203
|
+
Completion requires **both** conditions:
|
|
204
|
+
|
|
205
|
+
1. The agent emits `<promise>DONE</promise>` (or whatever marker you set)
|
|
206
|
+
2. Every file in `required_outputs` exists on disk
|
|
207
|
+
|
|
208
|
+
If the promise is seen but files are missing, the loop continues — the next iteration gets a rejection notice telling the agent what's still missing.
|
|
209
|
+
|
|
210
|
+
`RALPH_PROGRESS.md` is injected as rolling memory (max 4096 chars) and excluded from the `required_outputs` gate.
|
|
211
|
+
|
|
212
|
+
## Guardrails
|
|
213
|
+
|
|
214
|
+
### Block commands
|
|
215
|
+
|
|
216
|
+
Regex patterns matched against the full bash command. If any pattern matches, the command is blocked:
|
|
217
|
+
|
|
218
|
+
```yaml
|
|
219
|
+
guardrails:
|
|
220
|
+
block_commands:
|
|
221
|
+
- 'git\s+push'
|
|
222
|
+
- 'rm\s+-rf\s+/'
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Protect files
|
|
226
|
+
|
|
227
|
+
Glob patterns matched against file paths. Blocks `write` and `edit` tool calls:
|
|
228
|
+
|
|
229
|
+
```yaml
|
|
230
|
+
guardrails:
|
|
231
|
+
protected_files:
|
|
232
|
+
- '.env*'
|
|
233
|
+
- '*.pem'
|
|
234
|
+
- 'policy:secret-bearing-paths'
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`policy:secret-bearing-paths` is a built-in policy that blocks `.aws/`, `.ssh/`, `secrets/`, `.npmrc`, `.pem`, `.key`, and other secret-bearing paths.
|
|
238
|
+
|
|
239
|
+
## Common patterns
|
|
240
|
+
|
|
241
|
+
### Minimal loop
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
---
|
|
245
|
+
max_iterations: 10
|
|
246
|
+
---
|
|
247
|
+
Read TODO.md and implement the next task. Commit when done.
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Self-healing with test feedback
|
|
251
|
+
|
|
252
|
+
```yaml
|
|
253
|
+
---
|
|
254
|
+
commands:
|
|
255
|
+
- name: tests
|
|
256
|
+
run: npm test
|
|
257
|
+
timeout: 60
|
|
258
|
+
max_iterations: 20
|
|
259
|
+
completion_promise: DONE
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
{{ commands.tests }}
|
|
263
|
+
|
|
264
|
+
Fix failing tests before starting new work.
|
|
265
|
+
Read TODO.md and implement the next task.
|
|
266
|
+
Stop with <promise>DONE</promise> when all tests pass.
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Parameterized multi-env loop
|
|
270
|
+
|
|
271
|
+
```yaml
|
|
272
|
+
---
|
|
273
|
+
args:
|
|
274
|
+
- env
|
|
275
|
+
- focus
|
|
276
|
+
commands:
|
|
277
|
+
- name: tests
|
|
278
|
+
run: npm test -- --env={{ args.env }}
|
|
279
|
+
timeout: 120
|
|
280
|
+
max_iterations: 15
|
|
281
|
+
guardrails:
|
|
282
|
+
protected_files:
|
|
283
|
+
- 'policy:secret-bearing-paths'
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
Environment: {{ args.env }}
|
|
287
|
+
Focus: {{ args.focus }}
|
|
288
|
+
|
|
289
|
+
{{ commands.tests }}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Run: `/ralph --path my-task --arg env=staging --arg focus="auth"`
|
|
293
|
+
|
|
294
|
+
### Incremental migration
|
|
295
|
+
|
|
296
|
+
```yaml
|
|
297
|
+
---
|
|
298
|
+
commands:
|
|
299
|
+
- name: build
|
|
300
|
+
run: npm run build
|
|
301
|
+
timeout: 60
|
|
302
|
+
- name: tests
|
|
303
|
+
run: npm test
|
|
304
|
+
timeout: 120
|
|
305
|
+
required_outputs:
|
|
306
|
+
- MIGRATION_NOTES.md
|
|
307
|
+
stop_on_error: false
|
|
308
|
+
max_iterations: 30
|
|
309
|
+
completion_promise: DONE
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
Migrate one module per iteration from the legacy API to the new one.
|
|
313
|
+
|
|
314
|
+
Build output:
|
|
315
|
+
{{ commands.build }}
|
|
316
|
+
|
|
317
|
+
Test results:
|
|
318
|
+
{{ commands.tests }}
|
|
319
|
+
|
|
320
|
+
Stop with <promise>DONE</promise> when MIGRATION_NOTES.md exists and all tests pass.
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Run state
|
|
324
|
+
|
|
325
|
+
`.ralph-runner/` is auto-created in the task directory. Everything the loop needs to resume, inspect, or export:
|
|
326
|
+
|
|
327
|
+
| File | Purpose |
|
|
56
328
|
|---|---|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
329
|
+
| `status.json` | Current loop state (status, iteration, guardrails, timing) |
|
|
330
|
+
| `iterations.jsonl` | Append-only iteration records |
|
|
331
|
+
| `events.jsonl` | Append-only runner events (progress, gates, starts, finishes) |
|
|
332
|
+
| `transcripts/` | Per-iteration markdown transcripts |
|
|
333
|
+
| `active-loops/` | Registry of running loops (pruned after 30 minutes) |
|
|
334
|
+
|
|
335
|
+
### Log export
|
|
336
|
+
|
|
337
|
+
`/ralph-logs` copies `status.json`, `iterations.jsonl`, `events.jsonl`, and `transcripts/` to a destination directory. Skips symlinks and excludes control files. Default destination: `./ralph-logs-<ISO-timestamp>`.
|
|
338
|
+
|
|
339
|
+
## Termination statuses
|
|
340
|
+
|
|
341
|
+
| Status | Meaning |
|
|
66
342
|
|---|---|
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `timeout` |
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
343
|
+
| `complete` | Completion promise seen and gate passed |
|
|
344
|
+
| `max-iterations` | Reached `max_iterations` without completion |
|
|
345
|
+
| `no-progress-exhaustion` | No durable progress in any iteration |
|
|
346
|
+
| `stopped` | `/ralph-stop` observed |
|
|
347
|
+
| `timeout` | An iteration exceeded the `timeout` limit |
|
|
348
|
+
| `error` | Structural failure (parse error, missing file) |
|
|
349
|
+
| `cancelled` | `/ralph-cancel` observed |
|
|
350
|
+
|
|
351
|
+
## Draft workflow
|
|
352
|
+
|
|
353
|
+
`/ralph-draft` and `/ralph` without a path produce a draft:
|
|
354
|
+
|
|
355
|
+
1. Task text is classified as `analysis`, `fix`, `migration`, or `general`
|
|
356
|
+
2. A deterministic draft is generated from repo signals (package manager, test/lint commands)
|
|
357
|
+
3. If an authenticated model is available, the draft may be strengthened by LLM review
|
|
358
|
+
4. The draft is presented for interactive review — edit, start, or cancel
|
|
359
|
+
5. Guardrails and `required_outputs` from the baseline are preserved during strengthening
|
|
360
|
+
|
|
361
|
+
Drafts include a metadata comment (`<!-- pi-ralph-loop: ... -->`) used for re-validation on edits.
|
|
362
|
+
|
|
363
|
+
## Scaffold
|
|
364
|
+
|
|
365
|
+
`/ralph-scaffold <name-or-path>` creates a starter template:
|
|
366
|
+
|
|
367
|
+
```yaml
|
|
368
|
+
---
|
|
369
|
+
max_iterations: 10
|
|
370
|
+
timeout: 120
|
|
371
|
+
commands: []
|
|
372
|
+
---
|
|
373
|
+
# {{ ralph.name }}
|
|
374
|
+
|
|
375
|
+
Describe the task here.
|
|
376
|
+
|
|
377
|
+
## Evidence
|
|
378
|
+
Use {{ commands.* }} outputs as evidence.
|
|
379
|
+
|
|
380
|
+
## Completion
|
|
381
|
+
Stop with <promise>DONE</promise> when finished.
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Refuses to overwrite an existing `RALPH.md` or write outside the current working directory.
|
|
79
385
|
|
|
80
386
|
## License
|
|
81
|
-
|
|
387
|
+
|
|
388
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lnilluv/pi-ralph-loop",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Pi-native ralph loop — autonomous coding iterations with mid-turn supervision",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"pi": {
|
|
7
7
|
"extensions": [
|
|
8
8
|
"./src/index.ts"
|
|
9
|
+
],
|
|
10
|
+
"skills": [
|
|
11
|
+
"./skills"
|
|
9
12
|
]
|
|
10
13
|
},
|
|
11
14
|
"engines": {
|