pi-goal-list-loop-audit 0.29.7 → 0.29.9

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
@@ -39,10 +39,11 @@ Five top-level commands — `/goal`, `/list`, `/loop`, `/glla`, `/review`:
39
39
  /goal resume # resume
40
40
  /goal cancel # abort
41
41
  /goal decide # re-open the decision picker (v0.28.23)
42
- /goal audit # run the isolated auditor on the current goal nowno agent turn (v0.28.27)
42
+ /goal audit ["focus on payments"] # one-shot project audit (v0.29.8): fix the non-decisions, present the decisions findings in .pi-glla/audit-loop/findings.md
43
+ /goal verify # run the isolated auditor on the current goal now — no agent turn (v0.28.27, renamed from /goal audit in v0.29.8)
43
44
  /goal tweak "<new objective>" # edit in place (Confirm dialog)
44
45
  /goal archive # archived goals, newest first
45
- /glla # settings UI table · /glla key=value · /glla stats · /glla audits [N|full] · /glla postaudit · /glla wipe (nuclear reset, Confirm-gated) · /glla autoaccept=on
46
+ /glla # settings UI table · /glla status (unified what's-running view) · /glla key=value · /glla stats · /glla audits [N|full] · /glla postaudit · /glla wipe (nuclear reset, Confirm-gated) · /glla autoaccept=on
46
47
  /list fix the login bug, add dark mode, write docs # dump it — the agent shapes it into items, one Confirm
47
48
  /list plan.md # file detected → bulk import, one Confirm (sisyphus/Ralph style)
48
49
  /list <paste a checklist> # multi-line paste → same batch flow
@@ -66,7 +67,7 @@ matches `/list show`.
66
67
  /loop # draft the loop (agent grills; measure is test-run before you confirm)
67
68
  /loop start "keep polishing the UI" # infinite metricless loop (v0.23.6): no plateau, no cap — ends at time=/tokens= or /loop stop
68
69
  /loop respec # infinite metricless loop reconciling the codebase against the root SPEC.md / spec.md (v0.24.3) — 2 specs = you pick, 0 specs = drafting, 1 spec = auto-start (v0.24.4)
69
- /loop audit # project-audit loop (v0.29.0): each iteration audits fresh, appends findings to .pi-glla/audit-loop/findings.md, fixes the top ones — the orchestrator counts open findings and the plateau stop ends it when the well is dry
70
+ /loop audit # project-audit loop (v0.29.0): each iteration audits fresh, appends findings to .pi-glla/audit-loop/findings.md, fixes the top ones — the orchestrator counts open findings and the plateau stop ends it when the well is dry (one-shot version: /goal audit)
70
71
  /loop start "reduce TODOs" measure="grep -c TODO src.txt | head -1" direction=min
71
72
  /loop start "shrink the bundle" measure="..." direction=min time=4 tokens=500000 # arbitrary bounds
72
73
  /loop start "reduce TODOs" measure="..." direction=min branch=1 # scratch-branch mode
@@ -361,7 +362,7 @@ prompts/
361
362
  goal-loop-forever-draft.md # /loop drafting prompt
362
363
  scripts/
363
364
  smoke.sh # live integration harness (tmux + real models)
364
- tests/ # 613 tests across 58 files, no live pi required (mock-ctx harness drives the orchestrator)
365
+ tests/ # 614 tests across 58 files, no live pi required (mock-ctx harness drives the orchestrator)
365
366
  docs/DESIGN.md # architectural decisions
366
367
  PLAN.md # milestones, decisions, gates
367
368
  ```
@@ -9,6 +9,18 @@
9
9
  */
10
10
 
11
11
  export const BACKOFF_HARD_CAP_MS = 5 * 60 * 1000;
12
+
13
+ // v0.29.9: ms until the next clock-hour boundary (+ grace). Coding-plan
14
+ // rate-limit windows typically expire at the top of the hour, so a probe
15
+ // scheduled there catches the reset within seconds instead of mid-window.
16
+ // Robust when the premise is wrong too: a non-clock-aligned window is
17
+ // still caught within the hour.
18
+ export function msUntilNextHourBoundary(nowMs: number, graceMs = 60_000): number {
19
+ const d = new Date(nowMs);
20
+ d.setMinutes(0, 0, 0);
21
+ d.setHours(d.getHours() + 1);
22
+ return d.getTime() + graceMs - nowMs;
23
+ }
12
24
  export const BACKOFF_IDLE_RETRY_MS = 50; // when adding another iter to queue
13
25
  export const BACKOFF_ERROR_BASE_MS = 5_000; // first error retry
14
26
  export const BACKOFF_ERROR_MAX_MS = 60_000; // max error retry (separate from stuck cap)
@@ -216,10 +216,14 @@ export interface Goal {
216
216
  export type GoalRoute =
217
217
  | { kind: "draft" }
218
218
  | { kind: "set"; text: string }
219
- | { kind: "sub"; name: "status" | "pause" | "resume" | "cancel" | "decide" | "audit" | "tweak" | "archive" | "start"; rest: string };
219
+ | { kind: "sub"; name: "status" | "pause" | "resume" | "cancel" | "decide" | "verify" | "audit" | "tweak" | "archive" | "start"; rest: string };
220
220
 
221
- const GOAL_EXACT_SUBS = new Set(["status", "pause", "resume", "cancel", "decide", "audit"]);
222
- const GOAL_ARG_SUBS = new Set(["tweak", "archive", "start"]);
221
+ // v0.29.8: "audit" moved to ARG subs ("/goal audit [focus]" is the one-shot
222
+ // project audit user: "/goal audit IS the audit goal"); the v0.28.27
223
+ // manual current-goal verification moved to "verify" (it happens
224
+ // automatically at completion anyway — verify is the on-demand handle).
225
+ const GOAL_EXACT_SUBS = new Set(["status", "pause", "resume", "cancel", "decide", "verify"]);
226
+ const GOAL_ARG_SUBS = new Set(["audit", "tweak", "archive", "start"]);
223
227
 
224
228
  export function routeGoalArgs(raw: string): GoalRoute {
225
229
  const trimmed = raw.trim();
@@ -228,10 +232,10 @@ export function routeGoalArgs(raw: string): GoalRoute {
228
232
  const first = (space === -1 ? trimmed : trimmed.slice(0, space)).toLowerCase();
229
233
  const rest = space === -1 ? "" : trimmed.slice(space + 1).trim();
230
234
  if (GOAL_EXACT_SUBS.has(first) && rest === "") {
231
- return { kind: "sub", name: first as "status" | "pause" | "resume" | "cancel" | "decide", rest: "" };
235
+ return { kind: "sub", name: first as "status" | "pause" | "resume" | "cancel" | "decide" | "verify", rest: "" };
232
236
  }
233
237
  if (GOAL_ARG_SUBS.has(first)) {
234
- return { kind: "sub", name: first as "tweak" | "archive" | "start", rest };
238
+ return { kind: "sub", name: first as "audit" | "tweak" | "archive" | "start", rest };
235
239
  }
236
240
  return { kind: "set", text: trimmed };
237
241
  }
@@ -423,3 +423,22 @@ export function auditMeasureCmd(): string {
423
423
  export function auditTarget(): string {
424
424
  return `Audit the project for real problems and fix them, iteration by iteration. Every iteration: (1) run a FRESH audit pass over the codebase — spawn Explore subagents for breadth — hunting real issues: bugs, broken flows, regressions, drift between docs and code, dead code, security holes. Not style nits, not speculative refactors. (2) Append every NEW finding as one checkbox line "- [ ] SEVERITY: short description (file:line)" to ${AUDIT_FINDINGS_REL} (create the file on the first finding; append-only — never delete, rewrite, or reorder existing lines; never re-report a finding already listed). (3) Fix the highest-severity OPEN finding(s) — real fixes, committed — then check the box: "- [x] … — fixed in <commit>". (4) Honesty law: never fabricate findings to look busy; never mark a finding fixed without the fix commit existing. When a full audit pass surfaces nothing new AND no open findings remain, say so plainly — the orchestrator counts open findings every iteration and the plateau stop ends the loop when the well is dry.`;
425
425
  }
426
+
427
+ // ---- /goal audit-project (v0.29.8) ----
428
+
429
+ /**
430
+ * The one-shot project audit (user design 2026-07-30): "/loop audit keeps
431
+ * firing — this would be fire and address what you can, present what is to
432
+ * be decided; whether to fix a bug is not a decision." Same findings file
433
+ * as the audit loop (one ledger per project — the loop can keep working
434
+ * what the one-shot surfaced), but exactly ONE pass with a finish line the
435
+ * isolated auditor verifies, and the triage law the loop doesn't have:
436
+ * FIX findings (bugs, polish — nobody would say "leave that bug in") are
437
+ * fixed autonomously; DECIDE findings (direction, trade-offs — two
438
+ * reasonable answers exist) are presented, never touched. DECIDE lines use
439
+ * "- [?]" so they never inflate the loop's open-findings measure.
440
+ */
441
+ export function projectAuditTarget(focus?: string): string {
442
+ const scope = focus && focus.trim() ? focus.trim() : "the whole project";
443
+ return `Run ONE project audit pass and leave the project in a known state. Scope: ${scope}. (1) Run a FRESH audit pass over the codebase — spawn Explore subagents for breadth — hunting real problems: bugs, broken flows, regressions, drift between docs and code, dead code, security holes. Not style nits, not speculative refactors. (2) Append every NEW finding to ${AUDIT_FINDINGS_REL} (create the file on the first finding; append-only — never delete, rewrite, or reorder existing lines; never re-report a finding already listed), classified: "- [ ] FIX: SEVERITY: short description (file:line)" for bugs and polish — whether to fix these is NOT a decision — and "- [?] DECIDE: short description (what the choice is, what each side costs)" for direction, trade-offs, and scope questions where two reasonable answers exist. (3) Fix every NEW FIX finding from this pass — real fixes, committed with the repo's configured identity on the current branch (no invented identities or branches) — then check the box: "- [x] … — fixed in <commit>". (4) Change NOTHING for DECIDE findings — present them in the completion report instead. (5) Honesty law: never fabricate findings to look busy; never check a box without the fix commit existing; never silently turn a DECIDE into a fix. Done when: the audit pass is complete, every new FIX finding has a fix commit and a checked box in ${AUDIT_FINDINGS_REL}, and every DECIDE finding is listed in the file and presented in the completion report.`;
444
+ }
@@ -165,6 +165,7 @@ import {
165
165
  respecTarget,
166
166
  auditMeasureCmd,
167
167
  auditTarget,
168
+ projectAuditTarget,
168
169
  HELD_ON_RESTORE,
169
170
  type LoopState,
170
171
  } from "../goal-loop-forever.js";
@@ -182,6 +183,7 @@ import {
182
183
  shouldWedgeAlert,
183
184
  PENDING_LATCH_STUCK_MS,
184
185
  shouldFirePendingLatchWatchdog,
186
+ msUntilNextHourBoundary,
185
187
  } from "../goal-loop-backoff.js";
186
188
 
187
189
  // =================================================================
@@ -1106,7 +1108,7 @@ async function retryStoredCompletionAudit(ctx: ExtensionContext, origin: "quota-
1106
1108
  updateGoal({ status: "auditing" }, liveCtx);
1107
1109
  appendLedger(liveCtx.cwd, "goal_resumed", { via: origin === "manual" ? "manual-audit" : "quota-retry-direct-audit" });
1108
1110
  liveCtx.ui.notify(origin === "manual"
1109
- ? "Manual /goal audit — running the isolated auditor now (no agent turn needed)."
1111
+ ? "Manual /goal verify — running the isolated auditor now (no agent turn needed)."
1110
1112
  : "Auditor quota window elapsed — retrying the audit with your stored completion claim (no agent turn needed).", "info");
1111
1113
  const settings = loadSettings(liveCtx.cwd);
1112
1114
  const { model: auditorModel, error: modelError, via } = resolveAuditorModel(liveCtx, settings.auditorModel);
@@ -1164,7 +1166,7 @@ async function retryStoredCompletionAudit(ctx: ExtensionContext, origin: "quota-
1164
1166
  updateGoal({ auditHistory: history, pendingCompletion: undefined }, liveCtx);
1165
1167
  const objective = state.goal.objective;
1166
1168
  archiveCurrentGoal(liveCtx, "complete", `auditor ${result.model} approved (${origin})`);
1167
- liveCtx.ui.notify(`Goal complete — auditor ${result.model} approved${origin === "manual" ? " on /goal audit" : " on the quota retry"}.`, "info");
1169
+ liveCtx.ui.notify(`Goal complete — auditor ${result.model} approved${origin === "manual" ? " on /goal verify" : " on the quota retry"}.`, "info");
1168
1170
  notifyExternal(liveCtx, `Goal complete (auditor approved, ${origin}): ${objective.slice(0, 120)}`);
1169
1171
  return;
1170
1172
  }
@@ -1445,14 +1447,24 @@ async function cmdGoal(args: string, ctx: ExtensionContext): Promise<void> {
1445
1447
  if (!shown) ctx.ui.notify("No pending decision — the goal isn't paused on a choice (or no UI).", "info");
1446
1448
  return;
1447
1449
  }
1448
- // v0.28.27: /goal audit — run the isolated auditor on the current goal
1450
+ // v0.29.8: /goal audit [focus] — the ONE-SHOT project audit (user:
1451
+ // "/goal audit IS the audit goal — we are not auditing the current
1452
+ // goal, that happens automatically"). Fire-and-address: one audit
1453
+ // pass, FIX findings fixed autonomously (a bug is not a decision),
1454
+ // DECIDE findings presented, untouched. Runs as a normal goal through
1455
+ // cmdSet — the isolated auditor verifies the finish line.
1456
+ if (route.name === "audit") {
1457
+ return cmdSet(projectAuditTarget(route.rest || undefined), ctx, true);
1458
+ }
1459
+ // v0.28.27 (renamed /goal audit → /goal verify in v0.29.8): run the
1460
+ // isolated auditor on the current goal
1449
1461
  // RIGHT NOW, without engaging the agent. The user's "the work looks
1450
1462
  // done — just verify it" handle (and the manual counterpart of the
1451
1463
  // v0.28.26 stored-claim quota retry). Seeds a synthesized claim so a
1452
1464
  // quota block falls into the same pendingCompletion retry machinery.
1453
- if (route.name === "audit") {
1465
+ if (route.name === "verify") {
1454
1466
  if (!state.goal) {
1455
- ctx.ui.notify("No active goal — /goal audit needs a goal to verify.", "warning");
1467
+ ctx.ui.notify("No active goal — /goal verify needs a goal to verify.", "warning");
1456
1468
  return;
1457
1469
  }
1458
1470
  if (completionAuditInFlight) {
@@ -1461,7 +1473,7 @@ async function cmdGoal(args: string, ctx: ExtensionContext): Promise<void> {
1461
1473
  }
1462
1474
  updateGoal({
1463
1475
  pendingCompletion: {
1464
- completionSummary: "Manual audit requested by the user via /goal audit (no agent completion claim). Verify the objective against the repo directly.",
1476
+ completionSummary: "Manual audit requested by the user via /goal verify (no agent completion claim). Verify the objective against the repo directly.",
1465
1477
  at: nowIso(),
1466
1478
  },
1467
1479
  }, ctx);
@@ -4551,6 +4563,37 @@ function cmdAudits(args: string, ctx: ExtensionContext): void {
4551
4563
  ctx.ui.notify(`glla audits — last ${entries.length} verdict(s) in ${ctx.cwd}\n${formatAuditLog(entries)}`, "info");
4552
4564
  }
4553
4565
 
4566
+ // v0.29.8: /glla status — the unified "what's running" surface (user: "we
4567
+ // need to type goal status [to check], so that command at least is missing
4568
+ // for checking on whatever active process we have"). Read-only aggregate of
4569
+ // the ONE state — goal, list queue, loop, pending decisions — with pointers
4570
+ // to the deep surfaces.
4571
+ function cmdGllaStatus(ctx: ExtensionContext): void {
4572
+ const lines: string[] = [];
4573
+ const g = state.goal;
4574
+ if (g) {
4575
+ const tok = (g.usage?.tokensUsed ?? 0) > 0 ? ` · ${g.usage!.tokensUsed} tok` : "";
4576
+ const audit = g.status === "auditing" ? " (auditor running…)" : "";
4577
+ const pause = g.status === "paused" && g.pauseReason ? ` — ${g.pauseReason.slice(0, 90)}` : "";
4578
+ lines.push(`goal [${g.policy}] ${g.status}${audit}${tok}: ${g.objective.slice(0, 90)}${pause}`);
4579
+ } else {
4580
+ lines.push("goal: none");
4581
+ }
4582
+ const q = listQueue();
4583
+ lines.push(`list: ${q.length === 0 ? "empty" : `${q.length} queued — head: ${(q[0]?.objective ?? "").slice(0, 70)}`}`);
4584
+ const l = state.loop;
4585
+ if (l) {
4586
+ lines.push(`loop: ${l.active ? "ACTIVE" : `held/stopped — ${l.stopReason ?? "n/a"}`} · iter ${l.iteration}/${l.maxIterations > 0 ? l.maxIterations : "∞"} · best ${l.bestValue ?? "n/a"} · stall ${l.stallCount} — ${l.target.slice(0, 60)}`);
4587
+ } else {
4588
+ lines.push("loop: none");
4589
+ }
4590
+ if (g?.status === "paused" && g.pauseKind === "decision" && g.pauseOptions?.length) {
4591
+ lines.push(`decision pending (${g.pauseOptions.length} options) — /goal decide`);
4592
+ }
4593
+ lines.push("deep: /goal status · /list · /loop status · /glla stats · /glla audits · /glla log");
4594
+ ctx.ui.notify(`glla status\n${lines.join("\n")}`, "info");
4595
+ }
4596
+
4554
4597
  async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
4555
4598
  // The plugin's ONE config surface — global by default, rarely opened.
4556
4599
  // /glla show effective values + where each comes from
@@ -4573,6 +4616,11 @@ async function cmdSettings(args: string, ctx: ExtensionContext): Promise<void> {
4573
4616
  cmdAudits(trimmed.slice("audits".length).trim(), ctx);
4574
4617
  return;
4575
4618
  }
4619
+ // v0.29.8: /glla status — the unified what's-running view.
4620
+ if (/^status\b/.test(trimmed)) {
4621
+ cmdGllaStatus(ctx);
4622
+ return;
4623
+ }
4576
4624
  // v0.28.28: /glla log [N] — the raw event trail, human-readable. "Log it
4577
4625
  // so we can look back and see where we are doing things wrong."
4578
4626
  if (/^log\b/.test(trimmed)) {
@@ -4970,10 +5018,13 @@ export default function (pi: ExtensionAPI): void {
4970
5018
  description: "Set/draft a goal, or /goal status|pause|resume|cancel|tweak <text>|archive|start <objective>. Objectives without a 'Done when:' clause are grilled into a contract first; include the clause or use /goal start to skip the interview and activate instantly.",
4971
5019
  getArgumentCompletions: completions([
4972
5020
  ["start", "skip drafting — /goal start <objective> activates immediately"],
5021
+ ["audit", "one-shot project audit goal: /goal audit [focus] — fix the non-decisions, present the decisions (v0.29.8)"],
5022
+ ["verify", "run the isolated auditor on the current goal NOW (v0.28.27, renamed from /goal audit)"],
4973
5023
  ["status", "show the active goal and its task list"],
4974
5024
  ["pause", "pause the active goal"],
4975
5025
  ["resume", "resume a paused goal (and the list, when items are queued)"],
4976
5026
  ["cancel", "abort the active goal"],
5027
+ ["decide", "re-open the decision picker for a decision pause"],
4977
5028
  ["tweak", "change the objective: /goal tweak <text>"],
4978
5029
  ["archive", "list archived goals"],
4979
5030
  ]),
@@ -4990,6 +5041,7 @@ export default function (pi: ExtensionAPI): void {
4990
5041
  ["autoresume=", "default: hold when a session is loaded, auto-resume on reload/fork; on: always auto-resume; off: never"],
4991
5042
  ["decisionpopup=", "on|off: decision pauses pop the select() picker (default on; the widget card always lists the options, /goal decide reopens the picker)"],
4992
5043
  ["auditcap=", "N: pause goal after N consecutive auditor disapprovals (default 5, 0 = unlimited)"],
5044
+ ["status", "unified what's-running view: goal + list queue + loop + pending decisions (v0.29.8)"],
4993
5045
  ["log", "event-trail tail: /glla log [N] — who created/resumed/paused what, from where (v0.28.28)"],
4994
5046
  ["wipe", "WIPE live glla state (goal archived, list cleared, loop stopped) — one-shot cleanup for leftover-laden projects"],
4995
5047
  ["resume", "resume WHATEVER is paused/held (goal, list item, or held loop) — no need to know the type"],
@@ -5489,17 +5541,40 @@ export default function (pi: ExtensionAPI): void {
5489
5541
  // v0.29.1: brake-cycle CAP. The v0.28.25 ladder slows the thrash
5490
5542
  // (1m→16m) but never STOPS it — junk-runner/hellhunter/pully each
5491
5543
  // burned 4+ pause↔retry cycles against provider windows that last
5492
- // hours. After 6 consecutive brakes: park, no more auto-retries.
5544
+ // hours. After 6 consecutive brakes: park. v0.29.9: the park keeps
5545
+ // probing at the top of each hour (clock-aligned window resets).
5493
5546
  if (errorBrakeStreak >= 6) {
5547
+ // v0.29.9: park — but keep probing at the top of each hour
5548
+ // (user: "simply adding an hourly retry … just to pick up work
5549
+ // faster assuming the retry expired"). Coding-plan rate-limit
5550
+ // windows typically expire on clock-hour boundaries, so a probe
5551
+ // scheduled for :01 catches the reset within seconds. One dunk
5552
+ // per hour, free (429s are rejected pre-billing); a successful
5553
+ // probe resets the whole error cycle. If the wall is something
5554
+ // else (auth, outage), the hourly probe is a harmless failed
5555
+ // resume attempt that re-parks via the same brake.
5494
5556
  updateGoal({
5495
5557
  status: "paused",
5496
5558
  pauseKind: "error",
5497
5559
  pauseReason: `${reason} — 6 error-brakes in a row; the provider has been erroring for an extended window`,
5498
- pauseSuggestedAction: "Check the provider/account (quota, outage), then /goal resume. No more automatic retries.",
5560
+ pauseSuggestedAction: "Probing at the top of each hour — rate-limit windows typically expire on clock-hour boundaries. /goal resume retries now.",
5499
5561
  }, ctx);
5500
- ctx.ui.notify(`${goalNoun()} parked: ${reason} — 6 brakes in a row, no more auto-retries. Check the provider, then /goal resume.`, "warning");
5501
- notifyExternal(ctx, `${goalNoun()} parked: provider erroring across 6 error-brake cycles.`);
5562
+ ctx.ui.notify(`${goalNoun()} parked: ${reason} — 6 brakes in a row. Hourly top-of-hour probes will pick work back up when the window opens; /goal resume retries now.`, "warning");
5563
+ notifyExternal(ctx, `${goalNoun()} parked: provider erroring across 6 error-brake cycles — hourly top-of-hour probes scheduled.`);
5502
5564
  appendLedger(ctx.cwd, "error_brake_capped", { streak: errorBrakeStreak, reason });
5565
+ const probeMs = msUntilNextHourBoundary(Date.now());
5566
+ scheduleQuotaRetry(ctx, probeMs / 1000, reason, () => {
5567
+ // Re-check: only probe if STILL parked by the error-brake cap —
5568
+ // a user pause/resume/cancel meanwhile is never stomped.
5569
+ if (state.goal && state.goal.status === "paused" && state.goal.pauseKind === "error"
5570
+ && (state.goal.pauseReason ?? "").includes("error-brakes in a row")) {
5571
+ appendLedger(ctx.cwd, "hourly_rate_probe", { goalId: state.goal.id, streak: errorBrakeStreak });
5572
+ updateGoal({ status: "active" }, ctx);
5573
+ appendLedger(ctx.cwd, "goal_resumed", { via: "hourly-rate-probe" });
5574
+ ctx.ui.notify("Hourly probe: resuming (rate-limit windows typically expire at the top of the hour).", "info");
5575
+ scheduleContinuation(ctx, true);
5576
+ }
5577
+ }, "Hourly rate-limit probe");
5503
5578
  return;
5504
5579
  }
5505
5580
  // v0.28.25: the cooldown escalates per CONSECUTIVE brake — a fleet-wide
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-list-loop-audit",
3
- "version": "0.29.7",
3
+ "version": "0.29.9",
4
4
  "description": "Goal. Loop. Audit. Done. \u2014 a pi-coding-agent extension that supervises long-running work, with isolated auditor on each completion. Beat bamboozling by design: the auditor runs in a fresh session with no extensions, no skills, no editor \u2014 only the read tools needed to verify your goal.",
5
5
  "license": "MIT",
6
6
  "author": "dracon",