pi-review-loop 0.3.1 → 0.4.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
@@ -30,13 +30,15 @@ Agents make mistakes. They miss edge cases, introduce typos, forget error handli
30
30
 
31
31
  **Smart Exit Detection** - Won't be fooled by "Fixed 3 issues. No further issues found." Detects when issues were fixed and keeps looping.
32
32
 
33
+ **Fresh Context** - Optional mode that strips prior review iterations from context each pass. The agent is prompted to re-read any relevant plan, spec, or PRD documents, so it truly reviews with fresh eyes instead of through the lens of its previous passes.
34
+
33
35
  **Fully Configurable** - Every pattern is customizable. Change what triggers the loop, what exits it, and what prompt gets sent. Extend the defaults or replace them entirely.
34
36
 
35
37
  ## Typical Workflow
36
38
 
37
39
  The loop shines in two scenarios:
38
40
 
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.
41
+ **Before implementing** — You've got a plan doc and want to sanity-check it against the actual codebase. Run `/review-plan` 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.
40
42
 
41
43
  **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.
42
44
 
@@ -66,7 +68,7 @@ The package includes two prompt templates that are automatically installed to `~
66
68
  These prompts are designed to work with the review loop:
67
69
  - They instruct the agent to respond with "No issues found." when done (triggering exit)
68
70
  - They tell the agent to end with "Fixed [N] issue(s). Ready for another review." when issues are fixed (continuing the loop)
69
- - They include the "fresh eyes" phrase that triggers the loop when `autoTrigger` is enabled
71
+ - `double-check.md` includes the "fresh eyes" phrase that triggers the loop when `autoTrigger` is enabled
70
72
 
71
73
  **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.
72
74
 
@@ -140,6 +142,47 @@ Or just type something else. Any non-trigger input exits review mode.
140
142
 
141
143
  Changes max iterations for current session.
142
144
 
145
+ ## Fresh Context
146
+
147
+ By default, each review iteration sees the full conversation history including all prior iterations. This means by pass 3, the agent is reviewing code through the lens of its two prior reviews -- not truly fresh eyes. Fresh context mode fixes this.
148
+
149
+ When enabled, prior review iterations are stripped from context before each LLM call. The agent only sees: the original pre-review conversation, a brief pass note instructing it to re-read any relevant plan/spec/PRD documents, and the current iteration's review prompt and tool usage.
150
+
151
+ ### Enable Fresh Context
152
+
153
+ Per-session:
154
+ ```
155
+ /review-fresh on
156
+ ```
157
+
158
+ Or via the tool:
159
+ ```typescript
160
+ review_loop({ start: true, freshContext: true })
161
+ ```
162
+
163
+ Or permanently in settings:
164
+ ```json
165
+ {
166
+ "reviewerLoop": {
167
+ "freshContext": true
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### How It Works
173
+
174
+ ```
175
+ iteration 1: [pre-review context] [review prompt] ← full context
176
+ iteration 2: [pre-review context] [pass note] [review prompt] ← iter 1 stripped
177
+ iteration 3: [pre-review context] [pass note] [review prompt] ← iters 1-2 stripped
178
+ ```
179
+
180
+ The pre-review context is everything from before review mode was activated. Within a review iteration, multi-turn tool usage (read, bash, edit) is preserved -- only completed prior iterations are stripped.
181
+
182
+ The pass note tells the agent which pass it's on and instructs it to re-read any relevant plan, spec, PRD, or progress documents before reviewing. This way the agent re-grounds itself in the source of truth each pass using its own tool calls rather than programmatic injection.
183
+
184
+ If auto-compaction fires during a review loop (large sessions), the fresh context handler gracefully degrades to full context for that session.
185
+
143
186
  ## Configuration
144
187
 
145
188
  Configure in `~/.pi/agent/settings.json`. Works out of the box, but everything is customizable:
@@ -149,6 +192,7 @@ Configure in `~/.pi/agent/settings.json`. Works out of the box, but everything i
149
192
  "reviewerLoop": {
150
193
  "maxIterations": 7,
151
194
  "autoTrigger": true,
195
+ "freshContext": true,
152
196
  "reviewPrompt": "template:double-check",
153
197
  "triggerPatterns": {
154
198
  "mode": "extend",
@@ -172,6 +216,7 @@ Configure in `~/.pi/agent/settings.json`. Works out of the box, but everything i
172
216
  |--------|-------------|
173
217
  | `maxIterations` | Max review prompts before auto-exit (default: 7) |
174
218
  | `autoTrigger` | Enable keyword-based auto-trigger (default: false) |
219
+ | `freshContext` | Strip prior iterations from context each pass (default: false) |
175
220
  | `reviewPrompt` | The prompt to send each iteration |
176
221
  | `triggerPatterns` | What activates review mode (requires autoTrigger: true) |
177
222
  | `exitPatterns` | What indicates "review complete" |
@@ -250,6 +295,7 @@ The loop exits when:
250
295
  | `/review-max <n>` | Set max iterations (session only) |
251
296
  | `/review-auto [on\|off]` | Toggle auto-trigger from keywords (session only) |
252
297
  | `/review-auto <focus>` | Enable auto-trigger AND start review with custom focus |
298
+ | `/review-fresh [on\|off]` | Toggle fresh context mode (session only) |
253
299
  | `/review-status` | Show current state |
254
300
 
255
301
  ## Tool API
@@ -278,15 +324,19 @@ review_loop({ maxIterations: 10 })
278
324
  // Enable/disable auto-trigger
279
325
  review_loop({ autoTrigger: true })
280
326
  review_loop({ autoTrigger: false })
327
+
328
+ // Enable fresh context
329
+ review_loop({ start: true, freshContext: true })
281
330
  ```
282
331
 
283
332
  **Returns:**
284
333
  ```json
285
334
  {
286
335
  "active": true,
287
- "currentIteration": 2,
336
+ "currentIteration": 1,
288
337
  "maxIterations": 7,
289
338
  "autoTrigger": false,
339
+ "freshContext": true,
290
340
  "focus": "focus on error handling",
291
341
  "message": "Review mode active: iteration 2/7"
292
342
  }
@@ -316,6 +366,7 @@ otherwise → exit (max reached)
316
366
  - `session_start` - Reload settings
317
367
  - `input` - Detect triggers (if autoTrigger enabled), handle interrupts
318
368
  - `before_agent_start` - Check expanded prompts for triggers (if autoTrigger enabled)
369
+ - `context` - Strip prior iterations and inject pass note (if freshContext enabled)
319
370
  - `agent_end` - Analyze response, decide to loop or exit
320
371
 
321
372
  ## Limitations
package/index.ts CHANGED
@@ -7,13 +7,15 @@ export default function (pi: ExtensionAPI) {
7
7
  let reviewModeActive = false;
8
8
  let currentIteration = 0;
9
9
  let customPromptSuffix = "";
10
+ let freshContext = settings.freshContext;
11
+ let reviewBoundaryCount = -1;
12
+ let boundaryNeedsCapture = false;
10
13
 
11
14
  function updateStatus(ctx: ExtensionContext) {
12
15
  if (reviewModeActive) {
13
- ctx.ui.setStatus(
14
- "review-loop",
15
- `Review mode (${currentIteration}/${settings.maxIterations})`
16
- );
16
+ const parts = [`Review mode (${currentIteration + 1}/${settings.maxIterations})`];
17
+ if (freshContext) parts.push("fresh");
18
+ ctx.ui.setStatus("review-loop", parts.join(" | "));
17
19
  } else {
18
20
  ctx.ui.setStatus("review-loop", undefined);
19
21
  }
@@ -30,12 +32,8 @@ export default function (pi: ExtensionAPI) {
30
32
  function parseCustomText(args: string): string {
31
33
  const trimmed = args.trim();
32
34
  if (!trimmed) return "";
33
-
34
- // Try quoted strings first: "text" or 'text'
35
- const match = trimmed.match(/^"(.+)"$/s) || trimmed.match(/^'(.+)'$/s) ||
36
- trimmed.match(/"(.+?)"/s) || trimmed.match(/'(.+?)'/s);
37
-
38
- // If no quotes found, use the entire text as focus
35
+
36
+ const match = trimmed.match(/^"(.+)"$/s) || trimmed.match(/^'(.+)'$/s);
39
37
  return match ? match[1].trim() : trimmed;
40
38
  }
41
39
 
@@ -43,6 +41,8 @@ export default function (pi: ExtensionAPI) {
43
41
  reviewModeActive = false;
44
42
  currentIteration = 0;
45
43
  customPromptSuffix = "";
44
+ reviewBoundaryCount = -1;
45
+ boundaryNeedsCapture = false;
46
46
  updateStatus(ctx);
47
47
  ctx.ui.notify(`Review mode ended: ${reason}`, "info");
48
48
  }
@@ -50,12 +50,15 @@ export default function (pi: ExtensionAPI) {
50
50
  function enterReviewMode(ctx: ExtensionContext) {
51
51
  reviewModeActive = true;
52
52
  currentIteration = 0;
53
+ reviewBoundaryCount = -1;
54
+ boundaryNeedsCapture = false;
53
55
  updateStatus(ctx);
54
56
  ctx.ui.notify("Review mode activated", "info");
55
57
  }
56
58
 
57
59
  pi.on("session_start", async () => {
58
60
  settings = loadSettings();
61
+ freshContext = settings.freshContext;
59
62
  });
60
63
 
61
64
  pi.on("input", async (event, ctx) => {
@@ -86,6 +89,54 @@ export default function (pi: ExtensionAPI) {
86
89
  }
87
90
  });
88
91
 
92
+ pi.on("context", async (event) => {
93
+ if (!reviewModeActive || !freshContext) return;
94
+
95
+ const messages = event.messages;
96
+ if (messages.length === 0) return;
97
+
98
+ if (boundaryNeedsCapture) {
99
+ for (let i = messages.length - 1; i >= 0; i--) {
100
+ if (messages[i].role === "user") {
101
+ reviewBoundaryCount = i;
102
+ break;
103
+ }
104
+ }
105
+ boundaryNeedsCapture = false;
106
+ }
107
+
108
+ if (currentIteration === 0) return;
109
+ if (reviewBoundaryCount < 0) return;
110
+
111
+ let lastUserIdx = -1;
112
+ for (let i = messages.length - 1; i >= 0; i--) {
113
+ if (messages[i].role === "user") {
114
+ lastUserIdx = i;
115
+ break;
116
+ }
117
+ }
118
+ if (lastUserIdx < 0) return;
119
+ if (reviewBoundaryCount >= lastUserIdx) return;
120
+
121
+ const preReview = messages.slice(0, reviewBoundaryCount);
122
+ const currentIterationMsgs = messages.slice(lastUserIdx);
123
+
124
+ const assembled: typeof messages = [...preReview];
125
+
126
+ assembled.push({
127
+ role: "user",
128
+ content: [{
129
+ type: "text",
130
+ text: `[Review pass ${currentIteration + 1}. ${currentIteration} prior pass(es) completed, fixes applied to code. Re-read any relevant plan, spec, PRD, or progress documents before reviewing. Review with fresh eyes.]`,
131
+ }],
132
+ timestamp: Date.now(),
133
+ } as any);
134
+
135
+ assembled.push(...currentIterationMsgs);
136
+
137
+ return { messages: assembled };
138
+ });
139
+
89
140
  pi.on("agent_end", async (event, ctx) => {
90
141
  if (!ctx.hasUI) return;
91
142
  if (!reviewModeActive) return;
@@ -119,11 +170,12 @@ export default function (pi: ExtensionAPI) {
119
170
  }
120
171
 
121
172
  currentIteration++;
122
- if (currentIteration > settings.maxIterations) {
173
+ if (currentIteration >= settings.maxIterations) {
123
174
  exitReviewMode(ctx, `max iterations (${settings.maxIterations}) reached`);
124
175
  return;
125
176
  }
126
177
 
178
+ if (freshContext && reviewBoundaryCount < 0) boundaryNeedsCapture = true;
127
179
  updateStatus(ctx);
128
180
  pi.sendUserMessage(buildReviewPrompt(settings.reviewPromptConfig), {
129
181
  deliverAs: "followUp",
@@ -131,26 +183,28 @@ export default function (pi: ExtensionAPI) {
131
183
  });
132
184
 
133
185
  pi.registerCommand("review-start", {
134
- description: "Activate review loop and send review prompt. Optional: add custom focus text.",
186
+ description: "Activate review loop with optional custom focus text.",
135
187
  handler: async (args, ctx) => {
136
188
  if (reviewModeActive) {
137
189
  ctx.ui.notify("Review mode is already active", "info");
138
190
  } else {
139
191
  customPromptSuffix = parseCustomText(args);
140
192
  enterReviewMode(ctx);
193
+ if (freshContext && reviewBoundaryCount < 0) boundaryNeedsCapture = true;
141
194
  pi.sendUserMessage(buildReviewPrompt(settings.reviewPromptConfig));
142
195
  }
143
196
  },
144
197
  });
145
198
 
146
199
  pi.registerCommand("review-plan", {
147
- description: "Activate review loop for plans/specs/PRDs. Optional: add custom focus text.",
200
+ description: "Activate review loop for plans/specs/PRDs with optional custom focus text.",
148
201
  handler: async (args, ctx) => {
149
202
  if (reviewModeActive) {
150
203
  ctx.ui.notify("Review mode is already active", "info");
151
204
  } else {
152
205
  customPromptSuffix = parseCustomText(args);
153
206
  enterReviewMode(ctx);
207
+ if (freshContext && reviewBoundaryCount < 0) boundaryNeedsCapture = true;
154
208
  pi.sendUserMessage(buildReviewPrompt({ type: "template", value: "double-check-plan" }));
155
209
  }
156
210
  },
@@ -184,13 +238,12 @@ export default function (pi: ExtensionAPI) {
184
238
  description: "Show review mode status",
185
239
  handler: async (_args, ctx) => {
186
240
  if (reviewModeActive) {
187
- ctx.ui.notify(
188
- `Review mode active: iteration ${currentIteration}/${settings.maxIterations}`,
189
- "info"
190
- );
241
+ const parts = [`iteration ${currentIteration + 1}/${settings.maxIterations}`];
242
+ if (freshContext) parts.push("fresh context");
243
+ ctx.ui.notify(`Review mode active: ${parts.join(", ")}`, "info");
191
244
  } else {
192
245
  ctx.ui.notify(
193
- `Review mode inactive (max: ${settings.maxIterations}, auto-trigger: ${settings.autoTrigger ? "on" : "off"})`,
246
+ `Review mode inactive (max: ${settings.maxIterations}, auto-trigger: ${settings.autoTrigger ? "on" : "off"}, fresh: ${freshContext ? "on" : "off"})`,
194
247
  "info"
195
248
  );
196
249
  }
@@ -202,8 +255,7 @@ export default function (pi: ExtensionAPI) {
202
255
  handler: async (args, ctx) => {
203
256
  const arg = args.trim();
204
257
  const argLower = arg.toLowerCase();
205
-
206
- // Check for standard on/off/toggle keywords first
258
+
207
259
  if (argLower === "on" || argLower === "true" || argLower === "1") {
208
260
  settings.autoTrigger = true;
209
261
  ctx.ui.notify(`Auto-trigger enabled`, "info");
@@ -222,21 +274,36 @@ export default function (pi: ExtensionAPI) {
222
274
  );
223
275
  return;
224
276
  }
225
-
226
- // Anything else is treated as custom focus text
227
- const customText = parseCustomText(arg);
277
+
228
278
  settings.autoTrigger = true;
229
- customPromptSuffix = customText;
279
+ customPromptSuffix = parseCustomText(arg);
230
280
  if (reviewModeActive) {
231
281
  ctx.ui.notify(`Auto-trigger enabled, focus updated for next iteration`, "info");
232
282
  } else {
233
283
  enterReviewMode(ctx);
284
+ if (freshContext && reviewBoundaryCount < 0) boundaryNeedsCapture = true;
234
285
  pi.sendUserMessage(buildReviewPrompt(settings.reviewPromptConfig));
235
286
  ctx.ui.notify(`Auto-trigger enabled, review started with custom focus`, "info");
236
287
  }
237
288
  },
238
289
  });
239
290
 
291
+ pi.registerCommand("review-fresh", {
292
+ description: "Toggle fresh context mode for review iterations",
293
+ handler: async (args, ctx) => {
294
+ const arg = args.trim().toLowerCase();
295
+
296
+ if (arg === "on" || arg === "true" || arg === "1") {
297
+ freshContext = true;
298
+ } else if (arg === "off" || arg === "false" || arg === "0") {
299
+ freshContext = false;
300
+ } else {
301
+ freshContext = !freshContext;
302
+ }
303
+ ctx.ui.notify(`Fresh context ${freshContext ? "enabled" : "disabled"}`, "info");
304
+ },
305
+ });
306
+
240
307
  pi.registerTool({
241
308
  name: "review_loop",
242
309
  description:
@@ -268,15 +335,18 @@ export default function (pi: ExtensionAPI) {
268
335
  description: "Custom focus/instructions to append to the review prompt (e.g., \"focus on error handling\")",
269
336
  })
270
337
  ),
338
+ freshContext: Type.Optional(
339
+ Type.Boolean({
340
+ description: "Enable/disable fresh context mode (strips prior review iterations from context)",
341
+ })
342
+ ),
271
343
  }),
272
344
 
273
345
  async execute(_toolCallId, params, _onUpdate, ctx) {
274
- // Update maxIterations if provided
275
346
  if (typeof params.maxIterations === "number" && params.maxIterations >= 1) {
276
347
  settings.maxIterations = params.maxIterations;
277
348
  }
278
349
 
279
- // Update autoTrigger if provided
280
350
  if (typeof params.autoTrigger === "boolean") {
281
351
  settings.autoTrigger = params.autoTrigger;
282
352
  ctx.ui.notify(
@@ -285,12 +355,18 @@ export default function (pi: ExtensionAPI) {
285
355
  );
286
356
  }
287
357
 
288
- // Update custom focus if provided
289
358
  if (typeof params.focus === "string") {
290
359
  customPromptSuffix = params.focus.trim();
291
360
  }
292
361
 
293
- // Mode: start > stop > status
362
+ if (typeof params.freshContext === "boolean") {
363
+ freshContext = params.freshContext;
364
+ ctx.ui.notify(
365
+ `Fresh context ${freshContext ? "enabled" : "disabled"}`,
366
+ "info"
367
+ );
368
+ }
369
+
294
370
  if (params.start) {
295
371
  if (reviewModeActive) {
296
372
  return {
@@ -302,6 +378,7 @@ export default function (pi: ExtensionAPI) {
302
378
  currentIteration,
303
379
  maxIterations: settings.maxIterations,
304
380
  autoTrigger: settings.autoTrigger,
381
+ freshContext,
305
382
  focus: customPromptSuffix || undefined,
306
383
  message: "Review mode is already active",
307
384
  }),
@@ -311,6 +388,7 @@ export default function (pi: ExtensionAPI) {
311
388
  }
312
389
 
313
390
  enterReviewMode(ctx);
391
+ if (freshContext && reviewBoundaryCount < 0) boundaryNeedsCapture = true;
314
392
  pi.sendUserMessage(buildReviewPrompt(settings.reviewPromptConfig));
315
393
 
316
394
  return {
@@ -322,6 +400,7 @@ export default function (pi: ExtensionAPI) {
322
400
  currentIteration,
323
401
  maxIterations: settings.maxIterations,
324
402
  autoTrigger: settings.autoTrigger,
403
+ freshContext,
325
404
  focus: customPromptSuffix || undefined,
326
405
  message: customPromptSuffix
327
406
  ? `Review mode started with custom focus. Review prompt sent.`
@@ -343,6 +422,7 @@ export default function (pi: ExtensionAPI) {
343
422
  currentIteration: 0,
344
423
  maxIterations: settings.maxIterations,
345
424
  autoTrigger: settings.autoTrigger,
425
+ freshContext,
346
426
  message: "Review mode is not active",
347
427
  }),
348
428
  },
@@ -361,6 +441,7 @@ export default function (pi: ExtensionAPI) {
361
441
  currentIteration: 0,
362
442
  maxIterations: settings.maxIterations,
363
443
  autoTrigger: settings.autoTrigger,
444
+ freshContext,
364
445
  message: "Review mode stopped",
365
446
  }),
366
447
  },
@@ -368,7 +449,6 @@ export default function (pi: ExtensionAPI) {
368
449
  };
369
450
  }
370
451
 
371
- // Default: status
372
452
  return {
373
453
  content: [
374
454
  {
@@ -378,9 +458,10 @@ export default function (pi: ExtensionAPI) {
378
458
  currentIteration,
379
459
  maxIterations: settings.maxIterations,
380
460
  autoTrigger: settings.autoTrigger,
461
+ freshContext,
381
462
  focus: customPromptSuffix || undefined,
382
463
  message: reviewModeActive
383
- ? `Review mode active: iteration ${currentIteration}/${settings.maxIterations}`
464
+ ? `Review mode active: iteration ${currentIteration + 1}/${settings.maxIterations}`
384
465
  : "Review mode inactive",
385
466
  }),
386
467
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-review-loop",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Automated code review loop extension for pi coding agent",
5
5
  "scripts": {
6
6
  "postinstall": "node scripts/install.js",
@@ -1,10 +1,12 @@
1
1
  ---
2
2
  description: Double check / critique implementation plan with fresh eyes
3
3
  ---
4
- Great, now I want you to carefully read over the plan/spec and compare against the codebase with "fresh eyes," looking super carefully for any obvious bugs, errors, problems, issues, confusion, etc. Also double check that the patterns and coding styles match existing codebase conventions and preferences. Consider whether there is any unnecessary complexity or duplication, or if the changes can be more minimal without changing scope of requirements and without causing regressions or increasing the risk of bugs. Also keep in mind that this is not an MVP - so don't skip anything. If any issues are found, proceed to fix them without being asked to do so.
4
+ Great, now I want you to carefully read over the plan/spec and compare against the codebase with "fresh eyes," looking super carefully for any obvious bugs, errors, problems, issues, confusion, etc. Think through how best to implement this elegantly given our architecture and goals. Also keep in mind that this is not an MVP - so don't skip anything. If any issues are found, proceed to fix them without being asked to do so.
5
5
 
6
6
  **Response format:**
7
7
  - If you find ANY issues: fix them, then list what you fixed. Do NOT say "no issues found" - instead end with "Fixed [N] issue(s). Ready for another review."
8
- - If you find ZERO issues: respond with exactly "No issues found."
8
+ - If you find ZERO issues: describe what you examined and verified, then conclude with "No issues found."
9
+
10
+ Do not rush to a verdict. Read all relevant code first, trace through edge cases, and only then decide. I am pushing you to do a genuinely thorough review and not just lazily rubber-stamp it. Make sure you think deeply, then ultrathink some more.
9
11
 
10
12
  $@
@@ -3,8 +3,20 @@ description: Double check / review implementation with fresh eyes
3
3
  ---
4
4
  Great, now I want you to carefully read over all of the new code you just wrote and other existing code with "fresh eyes," looking super carefully for any obvious bugs, errors, problems, issues, confusion, etc. Also, if you notice any pre-existing issues/bugs those should be addressed.
5
5
 
6
+ Question everything: Does each line of code need to exist? Unused parameters, dead code, and unnecessary complexity should be removed, not dressed up with underscore prefixes or comments.
7
+
8
+ This codebase will outlive you. Every shortcut becomes someone else's burden. Every hack compounds into technical debt that slows the whole team down.
9
+
10
+ You are not just writing code. You are shaping the future of this project. The patterns you establish will be copied. The corners you cut will be cut again.
11
+
12
+ Fight entropy. Leave the codebase better than you found it.
13
+
14
+ You MUST read all relevant code and think deeply (ultrathink!!!) first before you make any edits.
15
+
6
16
  **Response format:**
7
17
  - If you find ANY issues: fix them, then list what you fixed. Do NOT say "no issues found" - instead end with "Fixed [N] issue(s). Ready for another review."
8
- - If you find ZERO issues: respond with exactly "No issues found."
18
+ - If you find ZERO issues: describe what you examined and verified, then conclude with "No issues found."
19
+
20
+ Do not rush to a verdict. Read all relevant code first, trace through edge cases, and only then decide. I am pushing you to do a genuinely thorough review and not just lazily rubber-stamp it. Make sure you think deeply, then ultrathink some more.
9
21
 
10
22
  $@
package/settings.ts CHANGED
@@ -6,11 +6,23 @@ export const SETTINGS_PATH = join(homedir(), ".pi", "agent", "settings.json");
6
6
 
7
7
  export const DEFAULT_MAX_ITERATIONS = 7;
8
8
 
9
- export const DEFAULT_REVIEW_PROMPT = `Great, now I want you to carefully read over all of the new code you just wrote and other existing code you just modified with "fresh eyes," looking super carefully for any obvious bugs, errors, problems, issues, confusion, etc. If any issues are found, proceed to fix them without being asked to do so.
9
+ export const DEFAULT_REVIEW_PROMPT = `Great, now I want you to carefully read over all of the new code you just wrote and other existing code with "fresh eyes," looking super carefully for any obvious bugs, errors, problems, issues, confusion, etc. Also, if you notice any pre-existing issues/bugs those should be addressed.
10
+
11
+ Question everything: Does each line of code need to exist? Unused parameters, dead code, and unnecessary complexity should be removed, not dressed up with underscore prefixes or comments.
12
+
13
+ This codebase will outlive you. Every shortcut becomes someone else's burden. Every hack compounds into technical debt that slows the whole team down.
14
+
15
+ You are not just writing code. You are shaping the future of this project. The patterns you establish will be copied. The corners you cut will be cut again.
16
+
17
+ Fight entropy. Leave the codebase better than you found it.
18
+
19
+ You MUST read all relevant code and think deeply (ultrathink!!!) first before you make any edits.
10
20
 
11
21
  **Response format:**
12
22
  - If you find ANY issues: fix them, then list what you fixed. Do NOT say "no issues found" - instead end with "Fixed [N] issue(s). Ready for another review."
13
- - If you find ZERO issues: respond with exactly "No issues found."`;
23
+ - If you find ZERO issues: describe what you examined and verified, then conclude with "No issues found."
24
+
25
+ Do not rush to a verdict. Read all relevant code first, trace through edge cases, and only then decide. I am pushing you to do a genuinely thorough review and not just lazily rubber-stamp it. Make sure you think deeply, then ultrathink some more.`;
14
26
 
15
27
  export const DEFAULT_TRIGGER_PATTERNS: RegExp[] = [
16
28
  /\bimplement\s+(the\s+)?plan\b/i,
@@ -61,6 +73,7 @@ export interface ReviewerLoopSettingsRaw {
61
73
  maxIterations?: number;
62
74
  reviewPrompt?: string;
63
75
  autoTrigger?: boolean;
76
+ freshContext?: boolean;
64
77
  triggerPatterns?: PatternConfig;
65
78
  exitPatterns?: PatternConfig;
66
79
  issuesFixedPatterns?: PatternConfig;
@@ -70,6 +83,7 @@ export interface ReviewerLoopSettings {
70
83
  maxIterations: number;
71
84
  reviewPromptConfig: ReviewPromptConfig;
72
85
  autoTrigger: boolean;
86
+ freshContext: boolean;
73
87
  triggerPatterns: RegExp[];
74
88
  exitPatterns: RegExp[];
75
89
  issuesFixedPatterns: RegExp[];
@@ -81,7 +95,8 @@ function parsePattern(input: unknown): RegExp | null {
81
95
  const match = input.match(/^\/(.+)\/([gimsuy]*)$/);
82
96
  if (match) {
83
97
  try {
84
- return new RegExp(match[1], match[2]);
98
+ const flags = match[2].replace(/g/g, "");
99
+ return new RegExp(match[1], flags);
85
100
  } catch {
86
101
  return null;
87
102
  }
@@ -204,6 +219,7 @@ export function loadSettings(): ReviewerLoopSettings {
204
219
  : DEFAULT_MAX_ITERATIONS,
205
220
  reviewPromptConfig: parseReviewPromptConfig(raw.reviewPrompt),
206
221
  autoTrigger: raw.autoTrigger === true,
222
+ freshContext: raw.freshContext === true,
207
223
  triggerPatterns: loadPatterns(raw.triggerPatterns, DEFAULT_TRIGGER_PATTERNS),
208
224
  exitPatterns: loadPatterns(raw.exitPatterns, DEFAULT_EXIT_PATTERNS),
209
225
  issuesFixedPatterns: loadPatterns(