pi-review-loop 0.1.1 → 0.2.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 +53 -33
- package/index.ts +44 -3
- package/package.json +1 -1
- package/settings.ts +3 -0
package/README.md
CHANGED
|
@@ -4,12 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
# Pi Review Loop
|
|
6
6
|
|
|
7
|
-
Automated code review loop for
|
|
7
|
+
Automated code review loop for [Pi coding agent](https://buildwithpi.ai/). Repeatedly prompts the agent to review its own work until it confirms no issues remain.
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
>
|
|
11
|
-
|
|
12
|
-
[agent implements...]
|
|
10
|
+
> /review-start
|
|
13
11
|
|
|
14
12
|
Review mode (1/7) ← status appears in footer
|
|
15
13
|
|
|
@@ -24,13 +22,9 @@ Review mode (2/7)
|
|
|
24
22
|
Review mode ended: no issues found ← auto-exits
|
|
25
23
|
```
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Agents make mistakes. They miss edge cases, introduce typos, forget error handling. Asking them to review their own code catches a surprising number of issues, but you have to remember to ask, and then ask again if they found something.
|
|
25
|
+
Agents make mistakes. They miss edge cases, introduce typos, forget error handling. Asking them to review their own code catches a surprising number of issues, but you have to remember to ask, and then ask again if they found something. This automates that:
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
**Auto-Trigger** - Detects phrases like "implement the plan" or the `/double-check` template. No need to manually activate.
|
|
27
|
+
**Auto-Trigger** - Optionally detects phrases like "implement the plan" or the `/double-check` template. Disabled by default; enable with `/review-auto on` or in settings.
|
|
34
28
|
|
|
35
29
|
**Persistent Loop** - After each response, sends a review prompt. If the agent found and fixed issues, it loops again. Only exits when the agent genuinely finds nothing.
|
|
36
30
|
|
|
@@ -42,9 +36,9 @@ Reviewer Loop automates this:
|
|
|
42
36
|
|
|
43
37
|
The loop shines in two scenarios:
|
|
44
38
|
|
|
45
|
-
**Before implementing** — You've got a plan doc and want to sanity-check it against the actual codebase. Run `/
|
|
39
|
+
**Before implementing** — You've got a plan doc and want to sanity-check it against the actual codebase. Run `/review-start` and let the agent compare the plan to what exists. It'll catch things like outdated assumptions, conflicting patterns, or unnecessary complexity. The funny thing is, it rarely finds everything on the first pass. Second pass catches different issues. Third pass, more still. That's the whole point of the loop.
|
|
46
40
|
|
|
47
|
-
**After implementing** — You just finished building a feature and want to catch bugs before calling it done. Run `/
|
|
41
|
+
**After implementing** — You just finished building a feature and want to catch bugs before calling it done. Run `/review-start` and the agent reviews its own work with fresh eyes. Typos, missed edge cases, forgotten error handling — it finds stuff you'd miss staring at the same code. Again, multiple passes tend to surface different issues each time.
|
|
48
42
|
|
|
49
43
|
The pattern is the same: keep reviewing until there's genuinely nothing left to find. The loop handles the "ask again" part automatically. You'll see `Review mode (2/7)` in the footer so you know it's working and how many passes it's done.
|
|
50
44
|
|
|
@@ -80,9 +74,13 @@ The package includes two prompt templates that are automatically installed to `~
|
|
|
80
74
|
| `double-check-plan.md` | `/double-check-plan` | Review implementation plan against codebase |
|
|
81
75
|
|
|
82
76
|
These prompts are designed to work with the review loop:
|
|
83
|
-
- They include the "fresh eyes" phrase that auto-triggers the loop
|
|
84
77
|
- They instruct the agent to respond with "No issues found." when done (triggering exit)
|
|
85
78
|
- They tell the agent to end with "Fixed [N] issue(s). Ready for another review." when issues are fixed (continuing the loop)
|
|
79
|
+
- They include the "fresh eyes" phrase that triggers the loop when `autoTrigger` is enabled
|
|
80
|
+
|
|
81
|
+
**Recommended workflow:** Use `/review-start` to activate review mode, which sends the review prompt automatically. Alternatively, enable auto-trigger (`/review-auto on`) and the `/double-check` template will activate the loop.
|
|
82
|
+
|
|
83
|
+
You can customize or replace these prompts, change trigger patterns, or use your own entirely. See [Configuration](#configuration). The agent can also start/stop the loop on demand via the `review_loop` tool. See [Tool API](#tool-api).
|
|
86
84
|
|
|
87
85
|
**Manual installation** (if cloning instead of npm):
|
|
88
86
|
|
|
@@ -92,25 +90,41 @@ cp ~/.pi/agent/extensions/pi-review-loop/prompts/*.md ~/.pi/agent/prompts/
|
|
|
92
90
|
|
|
93
91
|
## Quick Start
|
|
94
92
|
|
|
95
|
-
###
|
|
93
|
+
### Manual Activation
|
|
96
94
|
|
|
97
|
-
|
|
95
|
+
```
|
|
96
|
+
/review-start
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Activates review mode and immediately sends the review prompt.
|
|
100
|
+
|
|
101
|
+
### Automatic Activation (Optional)
|
|
102
|
+
|
|
103
|
+
Auto-trigger is disabled by default. Enable it for the current session:
|
|
98
104
|
|
|
99
105
|
```
|
|
100
|
-
|
|
101
|
-
> implement the spec
|
|
102
|
-
> let's implement this plan
|
|
106
|
+
/review-auto on
|
|
103
107
|
```
|
|
104
108
|
|
|
105
|
-
Or
|
|
109
|
+
Or permanently in `~/.pi/agent/settings.json`:
|
|
106
110
|
|
|
107
|
-
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"reviewerLoop": {
|
|
114
|
+
"autoTrigger": true
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
With auto-trigger enabled, trigger phrases activate review mode:
|
|
108
120
|
|
|
109
121
|
```
|
|
110
|
-
|
|
122
|
+
> implement the plan
|
|
123
|
+
> implement the spec
|
|
124
|
+
> let's implement this plan
|
|
111
125
|
```
|
|
112
126
|
|
|
113
|
-
|
|
127
|
+
Or use the `/double-check` prompt template.
|
|
114
128
|
|
|
115
129
|
### Check Status
|
|
116
130
|
|
|
@@ -144,6 +158,7 @@ Configure in `~/.pi/agent/settings.json`. Works out of the box, but everything i
|
|
|
144
158
|
{
|
|
145
159
|
"reviewerLoop": {
|
|
146
160
|
"maxIterations": 7,
|
|
161
|
+
"autoTrigger": true,
|
|
147
162
|
"reviewPrompt": "template:double-check",
|
|
148
163
|
"triggerPatterns": {
|
|
149
164
|
"mode": "extend",
|
|
@@ -166,8 +181,9 @@ Configure in `~/.pi/agent/settings.json`. Works out of the box, but everything i
|
|
|
166
181
|
| Option | Description |
|
|
167
182
|
|--------|-------------|
|
|
168
183
|
| `maxIterations` | Max review prompts before auto-exit (default: 7) |
|
|
184
|
+
| `autoTrigger` | Enable keyword-based auto-trigger (default: false) |
|
|
169
185
|
| `reviewPrompt` | The prompt to send each iteration |
|
|
170
|
-
| `triggerPatterns` | What activates review mode |
|
|
186
|
+
| `triggerPatterns` | What activates review mode (requires autoTrigger: true) |
|
|
171
187
|
| `exitPatterns` | What indicates "review complete" |
|
|
172
188
|
| `issuesFixedPatterns` | What indicates issues were fixed (prevents false exits) |
|
|
173
189
|
|
|
@@ -228,7 +244,7 @@ The loop exits when:
|
|
|
228
244
|
|
|
229
245
|
1. **Exit phrase without fixes** - Agent says "no issues" and didn't fix anything
|
|
230
246
|
2. **Max iterations** - Safety limit reached (default: 7)
|
|
231
|
-
3. **User interrupts** - You type something
|
|
247
|
+
3. **User interrupts** - You type something (only trigger phrases are ignored, and only when auto-trigger is on)
|
|
232
248
|
4. **Manual exit** - `/review-exit` command
|
|
233
249
|
5. **Abort** - Press ESC or agent response is empty
|
|
234
250
|
|
|
@@ -239,11 +255,12 @@ The loop exits when:
|
|
|
239
255
|
| `/review-start` | Activate and send review prompt immediately |
|
|
240
256
|
| `/review-exit` | Exit review mode |
|
|
241
257
|
| `/review-max <n>` | Set max iterations (session only) |
|
|
258
|
+
| `/review-auto [on\|off]` | Toggle auto-trigger from keywords (session only) |
|
|
242
259
|
| `/review-status` | Show current state |
|
|
243
260
|
|
|
244
261
|
## Tool API
|
|
245
262
|
|
|
246
|
-
The `review_loop` tool lets the agent
|
|
263
|
+
The `review_loop` tool lets the agent control review mode directly:
|
|
247
264
|
|
|
248
265
|
```typescript
|
|
249
266
|
// Check status (default)
|
|
@@ -260,6 +277,10 @@ review_loop({ stop: true })
|
|
|
260
277
|
|
|
261
278
|
// Just update max iterations
|
|
262
279
|
review_loop({ maxIterations: 10 })
|
|
280
|
+
|
|
281
|
+
// Enable/disable auto-trigger
|
|
282
|
+
review_loop({ autoTrigger: true })
|
|
283
|
+
review_loop({ autoTrigger: false })
|
|
263
284
|
```
|
|
264
285
|
|
|
265
286
|
**Returns:**
|
|
@@ -268,6 +289,7 @@ review_loop({ maxIterations: 10 })
|
|
|
268
289
|
"active": true,
|
|
269
290
|
"currentIteration": 2,
|
|
270
291
|
"maxIterations": 7,
|
|
292
|
+
"autoTrigger": false,
|
|
271
293
|
"message": "Review mode active: iteration 2/7"
|
|
272
294
|
}
|
|
273
295
|
```
|
|
@@ -279,7 +301,7 @@ review_loop({ maxIterations: 10 })
|
|
|
279
301
|
```
|
|
280
302
|
input event
|
|
281
303
|
↓
|
|
282
|
-
matches trigger? → enter review mode
|
|
304
|
+
autoTrigger on + matches trigger? → enter review mode
|
|
283
305
|
↓
|
|
284
306
|
agent responds
|
|
285
307
|
↓
|
|
@@ -294,14 +316,14 @@ otherwise → exit (max reached)
|
|
|
294
316
|
|
|
295
317
|
**Events used:**
|
|
296
318
|
- `session_start` - Reload settings
|
|
297
|
-
- `input` - Detect triggers, handle interrupts
|
|
298
|
-
- `before_agent_start` - Check expanded prompts for triggers
|
|
319
|
+
- `input` - Detect triggers (if autoTrigger enabled), handle interrupts
|
|
320
|
+
- `before_agent_start` - Check expanded prompts for triggers (if autoTrigger enabled)
|
|
299
321
|
- `agent_end` - Analyze response, decide to loop or exit
|
|
300
322
|
|
|
301
323
|
## Limitations
|
|
302
324
|
|
|
303
325
|
- **User templates only** - `template:name` loads from `~/.pi/agent/prompts/`, not project templates
|
|
304
|
-
- **Session-scoped
|
|
326
|
+
- **Session-scoped settings** - `/review-max` and `/review-auto` don't persist across sessions (use settings.json for persistence)
|
|
305
327
|
- **Pattern failures are silent** - Invalid regex patterns are skipped without error
|
|
306
328
|
|
|
307
329
|
## File Structure
|
|
@@ -325,8 +347,6 @@ pi-review-loop/
|
|
|
325
347
|
|
|
326
348
|
## Credits
|
|
327
349
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
- **[Ralph Wiggum Loop](https://ghuntley.com/ralph/)** by [@GeoffreyHuntley](https://x.com/GeoffreyHuntley) - Loosely based on the "Ralph" loop
|
|
350
|
+
- **[Ralph Wiggum Loop](https://ghuntley.com/ralph/)** by [@GeoffreyHuntley](https://x.com/GeoffreyHuntley)
|
|
331
351
|
- **["Fresh eyes" review prompt](https://x.com/doodlestein/status/1956228999945806049)** by [@doodlestein](https://x.com/doodlestein)
|
|
332
|
-
- **[pi](https://github.com/badlogic/pi-mono/)** by [@badlogicgames](https://x.com/badlogicgames)
|
|
352
|
+
- **[pi](https://github.com/badlogic/pi-mono/)** by [@badlogicgames](https://x.com/badlogicgames)
|
package/index.ts
CHANGED
|
@@ -39,7 +39,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
39
39
|
pi.on("input", async (event, ctx) => {
|
|
40
40
|
if (!ctx.hasUI) return { action: "continue" as const };
|
|
41
41
|
|
|
42
|
-
const isTrigger = settings.triggerPatterns.some((p) => p.test(event.text));
|
|
42
|
+
const isTrigger = settings.autoTrigger && settings.triggerPatterns.some((p) => p.test(event.text));
|
|
43
43
|
|
|
44
44
|
if (reviewModeActive && event.source === "interactive" && !isTrigger) {
|
|
45
45
|
exitReviewMode(ctx, "user interrupted");
|
|
@@ -56,6 +56,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
56
56
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
57
57
|
if (!ctx.hasUI) return;
|
|
58
58
|
if (reviewModeActive) return;
|
|
59
|
+
if (!settings.autoTrigger) return;
|
|
59
60
|
|
|
60
61
|
const isTrigger = settings.triggerPatterns.some((p) => p.test(event.prompt));
|
|
61
62
|
if (isTrigger) {
|
|
@@ -153,17 +154,38 @@ export default function (pi: ExtensionAPI) {
|
|
|
153
154
|
);
|
|
154
155
|
} else {
|
|
155
156
|
ctx.ui.notify(
|
|
156
|
-
`Review mode inactive (max: ${settings.maxIterations})`,
|
|
157
|
+
`Review mode inactive (max: ${settings.maxIterations}, auto-trigger: ${settings.autoTrigger ? "on" : "off"})`,
|
|
157
158
|
"info"
|
|
158
159
|
);
|
|
159
160
|
}
|
|
160
161
|
},
|
|
161
162
|
});
|
|
162
163
|
|
|
164
|
+
pi.registerCommand("review-auto", {
|
|
165
|
+
description: "Toggle auto-trigger from keywords (off by default)",
|
|
166
|
+
handler: async (args, ctx) => {
|
|
167
|
+
const arg = args.trim().toLowerCase();
|
|
168
|
+
if (arg === "on" || arg === "true" || arg === "1") {
|
|
169
|
+
settings.autoTrigger = true;
|
|
170
|
+
} else if (arg === "off" || arg === "false" || arg === "0") {
|
|
171
|
+
settings.autoTrigger = false;
|
|
172
|
+
} else if (arg === "") {
|
|
173
|
+
settings.autoTrigger = !settings.autoTrigger;
|
|
174
|
+
} else {
|
|
175
|
+
ctx.ui.notify("Usage: /review-auto [on|off]", "error");
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
ctx.ui.notify(
|
|
179
|
+
`Auto-trigger ${settings.autoTrigger ? "enabled" : "disabled"}`,
|
|
180
|
+
"info"
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
163
185
|
pi.registerTool({
|
|
164
186
|
name: "review_loop",
|
|
165
187
|
description:
|
|
166
|
-
"Control the automated code review loop. Start/stop review mode or check status. When started, the loop repeatedly prompts for code review until 'No issues found' or max iterations reached.",
|
|
188
|
+
"Control the automated code review loop. Start/stop review mode, toggle auto-trigger, or check status. When started, the loop repeatedly prompts for code review until 'No issues found' or max iterations reached.",
|
|
167
189
|
parameters: Type.Object({
|
|
168
190
|
start: Type.Optional(
|
|
169
191
|
Type.Boolean({
|
|
@@ -175,6 +197,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
175
197
|
description: "Stop review mode",
|
|
176
198
|
})
|
|
177
199
|
),
|
|
200
|
+
autoTrigger: Type.Optional(
|
|
201
|
+
Type.Boolean({
|
|
202
|
+
description: "Enable/disable auto-trigger from keywords (disabled by default)",
|
|
203
|
+
})
|
|
204
|
+
),
|
|
178
205
|
maxIterations: Type.Optional(
|
|
179
206
|
Type.Number({
|
|
180
207
|
description: "Set max iterations (can be combined with start)",
|
|
@@ -189,6 +216,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
189
216
|
settings.maxIterations = params.maxIterations;
|
|
190
217
|
}
|
|
191
218
|
|
|
219
|
+
// Update autoTrigger if provided
|
|
220
|
+
if (typeof params.autoTrigger === "boolean") {
|
|
221
|
+
settings.autoTrigger = params.autoTrigger;
|
|
222
|
+
ctx.ui.notify(
|
|
223
|
+
`Auto-trigger ${settings.autoTrigger ? "enabled" : "disabled"}`,
|
|
224
|
+
"info"
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
192
228
|
// Mode: start > stop > status
|
|
193
229
|
if (params.start) {
|
|
194
230
|
if (reviewModeActive) {
|
|
@@ -200,6 +236,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
200
236
|
active: true,
|
|
201
237
|
currentIteration,
|
|
202
238
|
maxIterations: settings.maxIterations,
|
|
239
|
+
autoTrigger: settings.autoTrigger,
|
|
203
240
|
message: "Review mode is already active",
|
|
204
241
|
}),
|
|
205
242
|
},
|
|
@@ -218,6 +255,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
218
255
|
active: true,
|
|
219
256
|
currentIteration,
|
|
220
257
|
maxIterations: settings.maxIterations,
|
|
258
|
+
autoTrigger: settings.autoTrigger,
|
|
221
259
|
message: "Review mode started. Review prompt sent.",
|
|
222
260
|
}),
|
|
223
261
|
},
|
|
@@ -235,6 +273,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
235
273
|
active: false,
|
|
236
274
|
currentIteration: 0,
|
|
237
275
|
maxIterations: settings.maxIterations,
|
|
276
|
+
autoTrigger: settings.autoTrigger,
|
|
238
277
|
message: "Review mode is not active",
|
|
239
278
|
}),
|
|
240
279
|
},
|
|
@@ -252,6 +291,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
252
291
|
active: false,
|
|
253
292
|
currentIteration: 0,
|
|
254
293
|
maxIterations: settings.maxIterations,
|
|
294
|
+
autoTrigger: settings.autoTrigger,
|
|
255
295
|
message: "Review mode stopped",
|
|
256
296
|
}),
|
|
257
297
|
},
|
|
@@ -268,6 +308,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
268
308
|
active: reviewModeActive,
|
|
269
309
|
currentIteration,
|
|
270
310
|
maxIterations: settings.maxIterations,
|
|
311
|
+
autoTrigger: settings.autoTrigger,
|
|
271
312
|
message: reviewModeActive
|
|
272
313
|
? `Review mode active: iteration ${currentIteration}/${settings.maxIterations}`
|
|
273
314
|
: "Review mode inactive",
|
package/package.json
CHANGED
package/settings.ts
CHANGED
|
@@ -60,6 +60,7 @@ export interface ReviewPromptConfig {
|
|
|
60
60
|
export interface ReviewerLoopSettingsRaw {
|
|
61
61
|
maxIterations?: number;
|
|
62
62
|
reviewPrompt?: string;
|
|
63
|
+
autoTrigger?: boolean;
|
|
63
64
|
triggerPatterns?: PatternConfig;
|
|
64
65
|
exitPatterns?: PatternConfig;
|
|
65
66
|
issuesFixedPatterns?: PatternConfig;
|
|
@@ -68,6 +69,7 @@ export interface ReviewerLoopSettingsRaw {
|
|
|
68
69
|
export interface ReviewerLoopSettings {
|
|
69
70
|
maxIterations: number;
|
|
70
71
|
reviewPromptConfig: ReviewPromptConfig;
|
|
72
|
+
autoTrigger: boolean;
|
|
71
73
|
triggerPatterns: RegExp[];
|
|
72
74
|
exitPatterns: RegExp[];
|
|
73
75
|
issuesFixedPatterns: RegExp[];
|
|
@@ -201,6 +203,7 @@ export function loadSettings(): ReviewerLoopSettings {
|
|
|
201
203
|
? raw.maxIterations
|
|
202
204
|
: DEFAULT_MAX_ITERATIONS,
|
|
203
205
|
reviewPromptConfig: parseReviewPromptConfig(raw.reviewPrompt),
|
|
206
|
+
autoTrigger: raw.autoTrigger === true,
|
|
204
207
|
triggerPatterns: loadPatterns(raw.triggerPatterns, DEFAULT_TRIGGER_PATTERNS),
|
|
205
208
|
exitPatterns: loadPatterns(raw.exitPatterns, DEFAULT_EXIT_PATTERNS),
|
|
206
209
|
issuesFixedPatterns: loadPatterns(
|