pi-goal-list-loop-audit 0.34.19 → 0.34.48

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
@@ -2,15 +2,17 @@
2
2
 
3
3
  > **Mission control for autonomous pi.**
4
4
 
5
- Interview-drafted goals, an audited task queue, and forever-loops (metric, spec, project-audit) that run for hours. Every goal starts as a **drafted contract you confirm** — nothing activates sight-unseen. The plugin then writes a durable goal to disk, drives the agent through an `agent_end`-driven loop, and on each `complete_goal` spawns an **isolated auditor in a fresh pi session** to verify the work is genuinely done. Stall recovery, structured decision pauses, and consent gates keep you in charge while it works.
5
+ Interview-drafted goals, an audited task queue, and forever-loops (metric, spec, project-audit) that run for hours. Every goal starts as a **drafted contract you confirm** — nothing activates sight-unseen. The plugin then writes a durable goal to disk, drives the agent through an `agent_end`-driven loop, and on each `complete_goal` queues a **detached auditor worker process** to verify the work without holding the main pi turn open. Stall recovery, structured decision pauses, and consent gates keep you in charge while it works.
6
6
 
7
- The auditor runs in a fresh session with no extensions, no skills, no prompts, no editor. It has only `read` / `grep` / `find` / `ls` / `bash`. It cannot see the implementing conversation. It cannot plant evidence. The implementer cannot fool it.
7
+ The auditor runs in a fresh extension-less pi RPC process with no extensions, skills, prompts, themes, or context files. It has only `read` / `grep` / `find` / `ls` / `bash`. It cannot see the implementing conversation, cannot mutate glla state, and cannot plant evidence. Its durable result is identity-checked and revalidated by the parent before it can archive a goal.
8
+
9
+ This is a detached process, not a nested session in the main pi process. `complete_goal` returns after writing the claim and job request; the status surface shows `auditor queued`, `auditor running`, or `audit recovery pending` while the worker runs or awaits a fresh lifecycle.
8
10
 
9
11
  ## Why this exists
10
12
 
11
13
  Most pi goal extensions — `pi-goal`, `pi-goal-x`, `pi-loop-mode`, `ralphi`, `tmustier-pi-ralph-wiggum` — let the same agent that did the work also be the verifier. **That's the bamboozle trap.** The agent that wrote the implementation also says "I'm done", and the loop trusts them.
12
14
 
13
- `pi-goal-list-loop-audit` separates **implementation** from **verification**. Two independent sessions, two independent read paths, two perspectives.
15
+ `pi-goal-list-loop-audit` separates **implementation** from **verification**. Two independent processes, two independent read paths, two perspectives.
14
16
 
15
17
  ### Architectural guarantee
16
18
 
@@ -18,7 +20,7 @@ Most pi goal extensions — `pi-goal`, `pi-goal-x`, `pi-loop-mode`, `ralphi`, `t
18
20
  |---|---|
19
21
  | Goal intake | Drafting + Confirm/Reject dialog; nothing activates unconfirmed |
20
22
  | Implementation | `agent_end`-driven continuation loop with 5-minute hard backoff cap |
21
- | Completion | Isolated auditor session + **regression_shield**: raw command output required per verification-contract item, enforced orchestrator-side |
23
+ | Completion | Detached extension-less auditor process + **regression_shield**: raw command output required per verification-contract item, enforced orchestrator-side |
22
24
 
23
25
  ## Quick start
24
26
 
@@ -40,11 +42,11 @@ Five top-level commands — `/goal`, `/list`, `/loop`, `/glla`, `/review`:
40
42
  /goal resume # resume
41
43
  /goal cancel # abort
42
44
  /goal decide # re-open the decision picker (v0.28.23)
43
- /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
44
- /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)
45
+ /goal audit "focus on payments" # one-shot project audit; optional focus text
46
+ /goal verify # queue a detached auditor for the current goal — no agent turn (v0.28.27, renamed from /goal audit in v0.29.8)
45
47
  /goal tweak "<new objective>" # edit in place (Confirm dialog)
46
48
  /goal archive # archived goals, newest first
47
- /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
49
+ /glla # settings UI table · arguments are actions: /glla status · /glla stats · /glla audits [N|full] · /glla postaudit · /glla wipe (nuclear reset, Confirm-gated)
48
50
  /list fix the login bug, add dark mode, write docs # dump it — the agent shapes it into items, one Confirm
49
51
  /list plan.md # file detected → bulk import, one Confirm (sisyphus/Ralph style)
50
52
  /list <paste a checklist> # multi-line paste → same batch flow
@@ -215,16 +217,94 @@ Each loop is a different policy class on the same status machine.
215
217
  | Auditor can rubber-stamp after `bash true` | **regression_shield** (shipped v0.2.0): auditor must quote raw tool output per verification-contract item; orchestrator rejects evidence-free approvals |
216
218
  | `pause_goal` is fire-and-forget | Clear `pauseReason` surfaced in status + agent feedback |
217
219
  | Vague objective + weak auditor = rubber-stamp | Drafting phase with Confirm dialog + isolated auditor + shield |
218
- | Esc mid-audit just dies | Escape dialog: complete-without-audit / continue (shipped v0.2.0) |
220
+ | Auditor holds the main turn open | Detached worker returns control immediately; `/goal cancel` discards the pending claim |
219
221
  | Auditor can't compact — context exhaustion mid-audit | Compaction enabled (v0.4.0); safe because the shield is orchestrator-side |
220
222
  | Agent can grow subtasks indefinitely | `propose_task_list` with 20/5 caps + Confirm dialog (v0.3.0) |
221
223
 
222
224
  ## Live TUI (always know it's on)
223
225
 
224
226
  A persistent `glla:` status segment + an above-editor widget show the current
225
- goal/loop at all times: objective, status, elapsed, tokens, next task or loop
226
- metric, pause reason, and live auditor progress during audits. If something is
227
- running, you can see it — no command needed.
227
+ goal/list item/loop at all times: objective, durable state, elapsed time,
228
+ tokens, next task or loop metric, pause reason, and live auditor progress
229
+ during audits. If something is running, you can see it — no command needed.
230
+
231
+ The status bar is the single activity HUD. It uses compact state capsules plus
232
+ an animated pulse waveform so live work is obvious at a glance without turning
233
+ the line into a progress meter. Fresh stream age is the proof of live work:
234
+
235
+ ```text
236
+ glla: [▁▂▄▆█▆ LIVE · WORKING] 1m 09s · last stream 11s ago · 3 queued
237
+ glla: [QUEUED] 44s · 18 queued
238
+ ```
239
+
240
+ The waveform is evidence-gated and indeterminate: it moves only while fresh
241
+ stream/tool activity is present, and says nothing about completion percentage.
242
+ Activity is otherwise intentionally honest:
243
+
244
+ | Indicator | Meaning |
245
+ |---|---|
246
+ | `LIVE · WORKING` | Fresh stream/tool evidence is arriving; the pulse and `last stream` age make that visible. |
247
+ | `BUSY` | pi is occupied, but no fresh stream evidence justifies a live pulse. |
248
+ | `QUEUED` | A continuation is waiting to start; no work is fabricated. |
249
+ | `IDLE` | The durable item remains active, but no recent work is observed. |
250
+ | `auditor …` | A detached, extension-less verifier is queued, running, quiet, or waiting for its verdict. |
251
+ | `QUOTA WALL` | The provider rejected the request for a quota/plan window; saved work is waiting for a durable probe. |
252
+
253
+ Quota walls deliberately do **not** get more blind request retries. A bare
254
+ 429/rate-limit response is treated as a transient throttle; explicit plan,
255
+ usage, billing, reset, and provider-code language is classified more strongly.
256
+ For example, MiniMax's `Token Plan rate limit reached … (2062)` asks for an
257
+ upgrade or pay-as-you-go billing and is not the same thing as a per-minute
258
+ throttle. Output/context-token stops are handled separately and never become a
259
+ quota wall. pi's request-local retry counter is bounded; glla owns the longer
260
+ recovery window: generic throttles use `15m → 30m → 1h → 2h → 4h → 5h`; a
261
+ plan wall with no reset hint starts at `1h → 2h → 4h → 5h`. Automatic probes
262
+ stop after 24h.
263
+ A provider hint is honored when it is within the five-hour probe budget; a
264
+ week-long hint is shown and held for manual action instead of scheduling a
265
+ hidden week-long timer. With global `autoResume=on`, pending probes survive a
266
+ session reload. After the safety horizon, `/list resume`, `/goal resume`, or
267
+ `/loop resume` explicitly starts a fresh bounded window. For continuous work,
268
+ configure ordered **Main model backups** in `/glla` using a model from a
269
+ different provider or billing/quota pool — another model on the same exhausted
270
+ plan is not a real fallback.
271
+
272
+ Classification is conservative: explicit 429/rate-limit/plan-limit/token-plan
273
+ signals are quota walls; ordinary `503 temporarily unavailable`, `403
274
+ forbidden`, auth failures, and ambiguous provider prose are not relabeled as
275
+ quota. Credit/billing exhaustion gets a manual-action hold. The raw provider
276
+ message remains in the ledger/durable state for diagnosis, while the card
277
+ shows the classified reason and recovery action.
278
+
279
+ The quota-specific card hides raw provider JSON while preserving it in durable
280
+ state and the ledger:
281
+
282
+ ```text
283
+ glla: ⟦⏳ QUOTA WALL · next probe in 10m 48s⟧ · 1 queued
284
+ ├─ QUOTA WALL · Token Plan usage limit · 1 waiting in list
285
+ ├─ waiting — nothing for you to do · next probe in 10m 48s
286
+ ```
287
+
288
+ Increasing pi's per-request retry count is usually the wrong fix for a
289
+ multi-hour plan cap: it prolongs the 429 noise and delays the durable pause;
290
+ it does not make the provider reset sooner. A provider that says "reset in a
291
+ week" therefore does not cause a week of unattended probes.
292
+
293
+ For long-running `/list` work, the card adds a compact queue trail with the
294
+ immediate next item and its truthful wait age while `/list` remains the
295
+ canonical full queue view:
296
+
297
+ ```text
298
+ ● Fix the current issue · list item · active · 42m
299
+ ├─ ✓ bash tests/display.test.ts (35s) · next: update docs
300
+ ├─ ↳ 23 waiting · up next: refresh the release notes · waiting 12m 04s
301
+ └─ 23 queued · /list · /glla
302
+ ```
303
+
304
+ The card does not duplicate the animated activity badge. This keeps the
305
+ visual surface calm while still making a long-running list feel alive and
306
+ answering the useful questions: **what is active, is it really moving, and
307
+ what is next?**
228
308
 
229
309
  ## Self-watchdog (liveness is built in)
230
310
 
@@ -232,7 +312,7 @@ A 15s heartbeat detects the precise stall condition — active goal/loop + idle
232
312
  session + nothing scheduled + quiet for 60s — and re-fires the continuation
233
313
  itself. Three consecutive zero-tool turns pause the goal / stop the loop.
234
314
  No external watchdog plugin needed. It also recovers **stranded audits**
235
- (v0.29.1): a goal stuck in `auditing` with no auditor session alive re-runs
315
+ (v0.29.1): a goal stuck in `auditing` with no detached worker alive re-runs
236
316
  the stored claim after 90s instead of black-holing. Storm protection: the
237
317
  send→pause→notify path rearms once per cycle and loud-stops after a 6-error
238
318
  brake streak, so a broken provider can't spin forever. A confirmed queued
@@ -277,33 +357,39 @@ The queued list is a backlog, not a second live thing — untouched.
277
357
 
278
358
  ## Config (one global place, rarely opened)
279
359
 
280
- ```
281
- /glla # open the settings UI
282
- /glla model=provider/id # auditor model override → GLOBAL
283
- /glla thinking=high # auditor thinking → GLOBAL
284
- /glla notify='cmd "$1"' # custom push cmd · unset = auto-detect (notify-send/osascript) · off = silent → GLOBAL
285
- /glla tokenlimit=10000000 # per-goal token budget (default: off) → GLOBAL
286
- /glla tokenlimit=0 # explicitly no cap (the default)
287
- /glla wedgealert=30 # hung-command alert minutes (default: 30, 0 = off)
288
- /glla autoresume=on # auto-resume goals/loops on ANY session start (default: load HELD, never auto-start — explicit /goal resume, /list resume, or /loop; off: never) — GLOBAL-only (v0.29.5): project-level keys are inert
289
- /glla auditcap=5 # pause the goal after N consecutive auditor disapprovals (default 5, 0 = unlimited)
290
- /glla aggressivemode=on # keep-going defaults: autoResume, cap 10, stuck 10, wedge off, quota auto-retry, cap→TODOs
291
- /glla quotaretryminutes=60 # minutes before auto-retrying a quota-exhausted auditor
292
- /glla stuckmax=10 # consecutive stuck interventions before a loop stops (default 5)
293
- /glla auditfeedbackchars=800 # cap the executor-visible auditor report (default 0 = full report)
294
- /glla autoaccept=on # drafts ACTIVATE without the Confirm dialog (v0.29.4: they start immediately — autoResume no longer gates drafts; every draft dialog also offers "always auto-accept" inline)
295
- /glla project tokenlimit=500 # rare per-project override
296
- ```
360
+ Open `/glla` to edit these settings in the table (the rows show effective values and provenance):
361
+
362
+ - Auditor model and thinking level
363
+ - Auditor fallback model
364
+ - Notify command, token limit, and wedge-alert minutes
365
+ - Auto-resume, auto-accept drafts, decision popup, and carryover policy
366
+ - Ordered main-session backups and recovery cadence
367
+ - Audit cap/report size, aggressive mode, quota retry, and stall brakes
368
+
369
+ The argument namespace is reserved for actions such as `/glla status`, `/glla
370
+ resume`, `/glla stats`, `/glla audits`, `/glla tooloverride`, and `/glla wipe`.
371
+ There is no top-level `/glla key=value` setting syntax.
297
372
 
298
373
  Resolution per key: **project > global > defaults** — EXCEPT `autoResume`,
299
374
  which is **global-only** (v0.29.5): per-project opt-ins from old versions
300
375
  silently overrode the global hold at launch (the junk-runner incident), so
301
376
  the launch-restore gate and the reviewer-enqueue gate read only the global
302
- file now. The auditor defaults to
303
- your pi session model. When the session provider is extension-registered the
304
- auditor can't auth it — you're told once (info level) with the fix:
305
- `/glla model=provider/id`, set once, rarely touched again. The plugin never
306
- picks a model itself. Thinking follows the session too (floor `high`).
377
+ file now. Main-session backups are global and ordered: a quota/provider error
378
+ switches to the next authenticated candidate before another supervised turn;
379
+ when every candidate is down, glla cancels the provider-held retry and uses a
380
+ bounded `15m → 30m → 1h → 2h → 4h → 5h` probe ladder. Automatic recovery stops
381
+ at 24h (or earlier when the provider supplies a reset beyond the five-hour
382
+ budget), preserves the saved work, and requires an explicit `/goal resume`,
383
+ `/list resume`, or `/loop resume` to start a fresh window. A quota window
384
+ returning within that horizon therefore resumes saved work without manual
385
+ intervention; no blind 50ms resend loop is introduced. The detached auditor uses an explicit cascade: primary
386
+ `auditorModel` → optional fallback pin → the pi session model. If a selected
387
+ model fails after launch, the worker retries it once and then advances through
388
+ that same cascade; every candidate is still audited in a detached,
389
+ extension-less process. There is no in-process fallback into the parent
390
+ session. If the bounded cascade is exhausted, the exact completion claim is
391
+ stored and the goal pauses for `/goal resume`; infrastructure is never treated
392
+ as a verdict.
307
393
 
308
394
  On disapproval, the executor receives the full auditor report by default
309
395
  (`auditFeedbackChars=0`, since v0.24.9 — a truncated report loses exactly the
@@ -313,9 +399,10 @@ history and is available through `/goal status` regardless.
313
399
 
314
400
  `autoaccept=on` skips BOTH the Confirm dialog and the drafting interview
315
401
  floor — every `propose_*` draft (goal, list batch, loop, task list)
316
- activates the moment the agent proposes it, with a notification and a
317
- `draft_autoaccepted` ledger entry (auto-accept is never silent). The seed
318
- carries the intent. Since v0.29.4 auto-accepted drafts **start immediately**
402
+ activates the moment the agent proposes it, and a completed `/list audit`
403
+ fan-out queues its generated finding items without a second confirmation.
404
+ Both paths notify loudly; auto-accept is never silent. The seed carries the
405
+ intent. Since v0.29.4 auto-accepted drafts **start immediately**
319
406
  — the draft path is decoupled from `autoResume`, which gates ONLY
320
407
  launch-time restore of persisted state ("load it but don't auto-start it").
321
408
  For fully unattended rigs you typically want both on; for attended rigs,
@@ -346,8 +433,8 @@ are workers** (v0.23.8):
346
433
  ## Token guard
347
434
 
348
435
  Every goal tracks real token usage; crossing the budget pauses the goal.
349
- Off by default (opt-in) — set a budget with `/glla tokenlimit=<n>`. A high
350
- value like 10000000 is a runaway threshold, not a big-goal threshold
436
+ Off by default (opt-in) — set Token limit in the `/glla` settings table. A
437
+ high value like 10000000 is a runaway threshold, not a big-goal threshold
351
438
  (real research/feature goals legitimately burn 2-4M). Loop 3 doesn't need
352
439
  this cap — it has its own brakes
353
440
  (max iterations + plateau).
@@ -359,12 +446,15 @@ but silent for a long stretch because ONE unbounded command (a test suite
359
446
  that never exits, a dev server) is holding the whole goal hostage. The
360
447
  heartbeat watches the wall clock: busy + no activity for 30 minutes →
361
448
  in-session warning + your configured notify push, once per interval while
362
- it persists. Tune with `/glla wedgealert=<minutes>` (0 = off).
449
+ it persists. Tune Wedge alert minutes in the `/glla` settings table (0 = off).
363
450
 
364
451
  Every other wait is bounded too: continuation retries are milliseconds,
365
452
  stuck backoff caps at 5 minutes then pauses, measure commands get a 10m
366
- hard timeout, and the auditor aborts after 10m with zero session activity
367
- (infrastructure error, never a verdict).
453
+ hard timeout, and the detached auditor aborts after 10m with no activity while no
454
+ read-only tool is running. A long-running verification tool is allowed to
455
+ finish, but the worker has a 30m wall-clock safety cap. Both paths are
456
+ infrastructure errors, never verdicts; interrupted claims remain stored for a
457
+ direct retry after `/goal resume`.
368
458
 
369
459
  ## Compatibility (what goes well, what conflicts)
370
460
 
@@ -391,10 +481,10 @@ and removed pi-tasks. If you truly need session-wide dependency DAGs beyond
391
481
  one ordered queue, it exists — but installing both is not the ideal combo.
392
482
 
393
483
  **Two footnotes**: (1) extension-registered providers work in the main session
394
- but not the auditor's extension-less session — if audits fail auth, set the
395
- override once with `/glla model=`. (2) `pi-notify-agent` notifies on every
484
+ but not the auditor's extension-less session — if audits fail auth, choose
485
+ an auditor model in `/glla` settings. (2) `pi-notify-agent` notifies on every
396
486
  turn; glla pushes fire only where there is something to DO (pauses, verdicts,
397
- storms, wedge) and work out of the box — with no `notify=` configured glla
487
+ storms, wedge) and work out of the box — with no notify command configured glla
398
488
  auto-detects `notify-send`/`osascript`; `notify=off` silences, `notify='<cmd>'`
399
489
  customizes.
400
490
 
@@ -404,7 +494,8 @@ customizes.
404
494
  extensions/
405
495
  loops/goal.ts # /goal + /list commands, agent tools, loop driver
406
496
  goal-loop-core.ts # types, JSONL state, pure helpers
407
- goal-loop-auditor.ts # isolated auditor (fresh session, no extensions)
497
+ goal-loop-auditor.ts # auditor prompt + legacy in-process helper
498
+ goal-loop-auditor-process.ts # detached worker protocol + shield revalidation
408
499
  goal-loop-shield.ts # regression_shield (pure, dependency-free)
409
500
  goal-loop-display.ts # status line + /goal status rendering
410
501
  goal-loop-forever.ts # /loop measure/parse/plateau helpers
@@ -415,8 +506,9 @@ prompts/
415
506
  goal-loop-forever.md # /loop driver prompt
416
507
  goal-loop-forever-draft.md # /loop drafting prompt
417
508
  scripts/
509
+ goal-auditor-worker.mjs # extension-less RPC auditor child process
418
510
  smoke.sh # live integration harness (tmux + real models)
419
- tests/ # 614 tests across 58 files, no live pi required (mock-ctx harness drives the orchestrator)
511
+ tests/ # current test count is reported by `bun test`; no live pi required for the suite
420
512
  docs/DESIGN.md # architectural decisions
421
513
  PLAN.md # milestones, decisions, gates
422
514
  ```
@@ -433,6 +525,17 @@ cd pi-goal-list-loop-audit
433
525
  pi install .
434
526
  ```
435
527
 
528
+ ## Publishing for other users
529
+
530
+ The npm package is public, but `publishConfig.access=public` does not publish
531
+ it by itself. Maintainers should configure npm Trusted Publishing for
532
+ `.github/workflows/publish.yml`, run `npm run release:check`, push a matching
533
+ `v<version>` tag, and publish a GitHub Release. That workflow then runs the
534
+ full checks and `npm publish --provenance --access public` without a long-lived
535
+ npm token. See [`docs/RELEASING.md`](docs/RELEASING.md); verify the result with
536
+ `npm view pi-goal-list-loop-audit version dist-tags.latest` before telling
537
+ users to upgrade.
538
+
436
539
  ## License
437
540
 
438
541
  MIT
package/docs/DESIGN.md CHANGED
@@ -59,9 +59,10 @@ architectural decisions that changed the SHAPE of the system:
59
59
  `autoResume` (on → any session start resumes; off → never) is **global-only**
60
60
  (v0.29.5) after a stale per-project opt-in silently overrode the global hold.
61
61
  - **Drafts and restores are decoupled** (v0.29.4): `autoAcceptDrafts` is the
62
- pre-consent for in-session drafts — they START immediately. `autoResume`
63
- gates only launch-time restore. "The session auto-starts in some cases ok;
64
- launching pi must not."
62
+ pre-consent for in-session drafts — they START immediately — and for the
63
+ generated finding batch at the end of `/list audit`. Direct bulk imports
64
+ remain Confirm-gated. `autoResume` gates only launch-time restore. "The
65
+ session auto-starts in some cases ok; launching pi must not."
65
66
  - **User aborts mean STOP** (v0.29.4/0.29.5): an aborted turn is exempt from
66
67
  stall accounting, stands the chain down with no auto re-fire, and the
67
68
  stand-down gates the heartbeat + post-compaction refires. The 5-abort loud
@@ -73,7 +74,8 @@ architectural decisions that changed the SHAPE of the system:
73
74
  Confirm-gated clean slate.
74
75
  - **The completion lifecycle owns its pauses** (v0.29.1): storm/stall
75
76
  escalation never pauses `auditing` goals; a stranded `auditing` state (no
76
- live auditor, 90s stale) re-runs the stored claim; send/pause/notify storms
77
+ live auditor; lifecycle rebinds retry stored claims immediately (the 90s
78
+ heartbeat path is only a fallback); send/pause/notify storms
77
79
  rearm once per cycle; the provider-error brake (v0.28.13) keeps cross-cycle
78
80
  memory and parks after 6 consecutive errors.
79
81
  - **The audit loop is the project reviewer** (v0.29.0): `/loop audit` runs
@@ -110,6 +112,91 @@ architectural decisions that changed the SHAPE of the system:
110
112
  deprecated deserialization compatibility fields; they do not select a
111
113
  transport.
112
114
 
115
+ ## Addendum v0.34.21 (completion-audit lifecycle observability)
116
+
117
+ - **The durable claim owns recovery state**: `pendingCompletion.phase` is
118
+ `running`, `recovery-pending`, or `quota-waiting`. Missing phase is legacy
119
+ state and is treated as recovery-pending after a fresh lifecycle event.
120
+ The isolated attempt id and wall deadline prevent an old generation from
121
+ finalizing a newer attempt.
122
+ - **Rebind recovery is immediate but consent-aware**: a replacement
123
+ `session_start` converts an old running claim to recovery-pending and
124
+ retries it immediately when the lifecycle handoff or global `autoResume`
125
+ supplies consent. A cold startup with autoResume off paints the pending
126
+ claim and waits for `/goal resume`.
127
+ - **Auditor bounds have two layers**: no-event inactivity aborts after 10m
128
+ only when no read-only tool is active; a live verification tool may finish,
129
+ but the complete isolated run has a 30m wall-clock cap. Both outcomes are
130
+ infrastructure failures, never verdicts, and the stored claim remains
131
+ retryable.
132
+
133
+ ## Addendum v0.34.22 (detached completion auditor)
134
+
135
+ - **Completion verification is process-isolated, not nested**: `complete_goal`
136
+ persists the claim and job request, then returns immediately. A detached
137
+ extension-less worker launches `pi --mode rpc` with only `read`, `grep`,
138
+ `find`, `ls`, and `bash`; it never receives the parent `ExtensionContext`,
139
+ never loads glla extensions or project context files, and never writes goal
140
+ state. This removes the previous nested `AgentSession` from the main pi
141
+ process and prevents a provider stall in the auditor from occupying the
142
+ executor's turn.
143
+ - **Durable job protocol**: request, progress, lock, and result files live
144
+ under `.pi-glla/audit-jobs/<attemptId>/`. Requests and results are hashed and
145
+ atomically written. The parent validates attempt/request identity, verdict
146
+ markers, read-tool use, and `regression_shield` before applying any result.
147
+ A result from a stale generation is ignored; fresh lifecycle recovery creates
148
+ a new attempt. Cancellation clears the pending claim and best-effort stops
149
+ the worker.
150
+ - **Truthful asynchronous UI**: `auditor queued`, `auditor running`, and
151
+ `audit recovery pending` are distinct. The main session can continue
152
+ rendering and accepting input while the worker audits; completion/archive or
153
+ disapproval/continuation happens only after durable result consumption.
154
+ - **Bounded worker liveness**: no session event for 10 minutes while no
155
+ read-only tool is active aborts the worker; a 30-minute wall-clock bound
156
+ always wins. Both are infrastructure failures, never verdicts, and the claim
157
+ remains retryable.
158
+
159
+ ## Addendum v0.34.24 (dispatch proof and display projection safety)
160
+
161
+ - **Accepted is not started**: every automated follow-up records a versioned,
162
+ generation/owner-bound dispatch in `.pi-glla/continuation-dispatch.json`
163
+ before calling `sendMessage({ triggerTurn: true })`. `before_agent_start`
164
+ with the matching marker is the strongest proof; compatible low-level start
165
+ events are accepted for older pi builds. The sidecar is cleared only after
166
+ proof or an explicit terminal send outcome.
167
+ - **No blind trigger storm**: an accepted dispatch has one bounded start-proof
168
+ timer. If no start event arrives, glla records an unresolved dispatch, keeps
169
+ the goal/list item durable, stands down automatic sends, and tells the user
170
+ how to use a fresh lifecycle or explicit resume. It does not inject terminal
171
+ input, restart pi, or treat a successful API return as a turn.
172
+ - **Generation-safe recovery**: replacement/shutdown clears in-memory pending
173
+ state; a new session records and clears any old sidecar, then the existing
174
+ restore/autoResume consent rules decide whether to retry. Late foreign or
175
+ old-generation events cannot acknowledge a new dispatch.
176
+ - **Display-only sanitization**: terminal/ANSI/OSC, bidi, and zero-width
177
+ controls are removed from status, widget, notification, confirmation, and
178
+ status-tool projections. Persisted objectives, contracts, prompts, ledger
179
+ values, and auditor inputs remain unchanged.
180
+
181
+ ## Addendum v0.34.31 (main-session model recovery)
182
+
183
+ - **Ordered global backups**: `mainModelFallbacks` is an explicit ordered list
184
+ of `provider/model` references. A provider/quota error can rotate the MAIN
185
+ session through authenticated candidates; the detached auditor's model
186
+ cascade remains a separate subsystem.
187
+ - **No accepted-send inference**: model rotation occurs only after a provider
188
+ failure is observed (or after a 15-minute, five-minute-silent provider-held
189
+ retry storm). A successful `sendMessage()` return is never treated as a
190
+ started turn.
191
+ - **Durable recovery instead of abandonment**: when all candidates fail,
192
+ `.pi-glla/active.jsonl` stores the primary, active candidate, attempted set,
193
+ retry time, and supervisor kind. Recovery probes back off 15m → 30m →
194
+ hourly forever (configurable base), while a paused goal/held loop remains
195
+ resumable. A fresh startup obeys the existing `autoResume` consent gate.
196
+ - **Successful-turn reset**: a real non-error agent end clears the recovery
197
+ cycle. Manual model selection cancels it; goal/list/loop cancellation clears
198
+ its timer and durable state.
199
+
113
200
  ## Addendum v0.4.0 (completion)
114
201
 
115
202
  - **Auditor compaction enabled** (flaw #3 — the last open one). Safety:
@@ -137,10 +224,10 @@ Single loop only — **loop 1**, the single ordered goal.
137
224
 
138
225
  The single most important property of this plugin is that the implementing agent cannot bamboozle the verifier. The way to achieve this structurally:
139
226
 
140
- 1. The auditor runs in a **fresh pi agent session**.
141
- 2. The auditor has **no extensions, no skills, no prompts, no themes**.
227
+ 1. The auditor runs in a **detached pi RPC process with a fresh agent session**.
228
+ 2. The auditor has **no extensions, no skills, no prompts, no themes, and no context files**.
142
229
  3. The auditor has only **read-only tools**: `read`, `grep`, `find`, `ls`, `bash` (and `bash` is for re-running user's verifier scripts, not arbitrary).
143
- 4. The auditor **cannot see the implementing conversation**.
230
+ 4. The auditor **cannot see the implementing conversation or mutate glla state**.
144
231
 
145
232
  This is borrowed directly from `pi-goal-x/extensions/goal-auditor.ts:148-156`. The pattern is sound; we don't improve on it in v0.1.0, we just **fork the proven source and add regression_shield**.
146
233
 
@@ -205,7 +292,9 @@ This is a **clean break** by decision of the user. We do not interop with `pi-go
205
292
  | `extensions/loops/goal.ts` | Loops 1+2 (single goal + list of goals) | shipped |
206
293
  | `extensions/loops/forever.ts` | Loop 3 (metric loop helpers) | shipped |
207
294
  | `extensions/goal-loop-core.ts` | Shared state machine, types, JSONL | shipped |
208
- | `extensions/goal-loop-auditor.ts` | Isolated auditor with regression_shield | shipped |
295
+ | `extensions/goal-loop-auditor.ts` | Auditor prompt + compatibility helper | shipped |
296
+ | `extensions/goal-loop-auditor-process.ts` | Detached worker protocol, IPC, and shield revalidation | shipped |
297
+ | `scripts/goal-auditor-worker.mjs` | Extension-less RPC auditor child | shipped |
209
298
  | `extensions/goal-loop-display.ts` | Status line + /goal status rendering | shipped |
210
299
  | `prompts/goal-loop-continuation.md` | Templated continuation prompt | ~80 |
211
300
  | `prompts/goal-loop-auditor.md` | Templated auditor prompt | ~80 |
@@ -226,7 +315,7 @@ type Status =
226
315
 
227
316
  States owned by the orchestrator:
228
317
  - `active` → next iteration
229
- - `auditing` → auditor running
318
+ - `auditing` → detached auditor queued/running (or recovery pending)
230
319
  - `complete` → archived
231
320
  - `paused` → user-resumable
232
321
  - `aborted` → user-cancelled
@@ -253,7 +342,7 @@ This protects against model-generated summaries losing fidelity.
253
342
 
254
343
  | Trigger | Action |
255
344
  |---|---|
256
- | `Esc` during auditor | Pause; user picks "complete without audit" or "continue" |
345
+ | Detached auditor running | Main turn remains free; `/goal cancel` discards the pending claim and stops the worker best-effort |
257
346
  | `Esc` during agent turn | Pause |
258
347
  | User `/goal pause` | Pause |
259
348
  | User `/goal cancel` | Abort (wipes active goal) |
@@ -0,0 +1,49 @@
1
+ # Releasing to npm
2
+
3
+ This repository publishes `pi-goal-list-loop-audit` through the GitHub Release
4
+ workflow at `.github/workflows/publish.yml`.
5
+
6
+ ## One-time npm setup
7
+
8
+ In npm package settings, add a **Trusted Publisher** for:
9
+
10
+ - GitHub owner/repository: `DraconDev/pi-goal-list-loop-audit`
11
+ - workflow file: `.github/workflows/publish.yml`
12
+ - environment: leave unset unless the repository deliberately protects the job
13
+ with an npm environment
14
+
15
+ The workflow uses npm OIDC provenance. Do not add a long-lived `NPM_TOKEN` to
16
+ the repository.
17
+
18
+ ## Release checklist
19
+
20
+ ```bash
21
+ npm version <major.minor.patch> --no-git-tag-version
22
+ npm run release:check
23
+ # review the diff, then commit package.json + package-lock.json + changelog
24
+ # create and push the matching tag, for example:
25
+ git tag v<major.minor.patch>
26
+ git push origin main v<major.minor.patch>
27
+ ```
28
+
29
+ Create a GitHub Release from that tag. Publishing happens only after the
30
+ release is marked **published**; the workflow checks that the tag equals the
31
+ `package.json` version, runs the complete test/typecheck/package inspection,
32
+ and then runs:
33
+
34
+ ```bash
35
+ npm publish --provenance --access public
36
+ ```
37
+
38
+ Verify availability from a separate machine or shell:
39
+
40
+ ```bash
41
+ npm view pi-goal-list-loop-audit version dist-tags.latest
42
+ npm install -g pi-goal-list-loop-audit
43
+ # or in pi:
44
+ pi install npm:pi-goal-list-loop-audit
45
+ ```
46
+
47
+ `publishConfig.access=public` is necessary for the scoped/public policy, but
48
+ it does not publish anything by itself. A commit, tag, or GitHub Release alone
49
+ is not proof that npm has the package; the registry check above is the proof.