pi-goal-list-loop-audit 0.35.13 → 0.35.32

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +366 -0
  2. package/INSTALL.md +3 -3
  3. package/LIST-PHILOSOPHY.md +90 -0
  4. package/PLAN.md +316 -0
  5. package/README.md +108 -13
  6. package/docs/DESIGN-subagent-visibility.md +76 -0
  7. package/docs/DESIGN.md +59 -8
  8. package/docs/GLLA-POSITIONING-AND-DECOMPOSITION-2026-08-08.md +6 -1
  9. package/docs/INDEX.md +4 -0
  10. package/docs/VISION-ASSIST.md +2 -2
  11. package/extensions/auditor-extensions.ts +289 -0
  12. package/extensions/goal-agents-panel.ts +185 -0
  13. package/extensions/goal-commands.ts +120 -6
  14. package/extensions/goal-continuation.ts +45 -2
  15. package/extensions/goal-heartbeat.ts +176 -5
  16. package/extensions/goal-loop-auditor-process.ts +26 -0
  17. package/extensions/goal-loop-auditor.ts +3 -5
  18. package/extensions/goal-loop-backoff.ts +79 -0
  19. package/extensions/goal-loop-core.ts +97 -4
  20. package/extensions/goal-loop-display.ts +107 -8
  21. package/extensions/goal-loop-forever.ts +39 -1
  22. package/extensions/goal-loop-shield.ts +114 -25
  23. package/extensions/goal-loop.ts +66 -1
  24. package/extensions/goal-recovery.ts +8 -2
  25. package/extensions/goal-settings.ts +23 -0
  26. package/extensions/goal-state.ts +11 -0
  27. package/extensions/loops/goal-activation.ts +226 -25
  28. package/extensions/loops/goal-auditor-hooks.ts +39 -3
  29. package/extensions/loops/goal-list-queue.ts +17 -1
  30. package/extensions/loops/goal-orchestrator.ts +28 -1
  31. package/extensions/loops/goal-settings-ui.ts +96 -5
  32. package/extensions/loops/goal-tools.ts +82 -28
  33. package/extensions/loops/goal-ui.ts +105 -1
  34. package/extensions/loops/goal.ts +7 -7
  35. package/extensions/multi-model-picker.ts +45 -7
  36. package/extensions/settings-menu.ts +10 -0
  37. package/package.json +8 -3
  38. package/schemas/goal.schema.json +2 -0
  39. package/scripts/goal-auditor-launch.mjs +19 -1
  40. package/scripts/goal-auditor-worker.mjs +15 -0
  41. package/scripts/verify-auditor-extensions-offline.mjs +59 -0
package/PLAN.md ADDED
@@ -0,0 +1,316 @@
1
+ # PLAN — pi-goal-list-loop-audit
2
+
3
+ Living plan for the project. Update this file as decisions land or milestones close.
4
+ New here? Start with README.md and INSTALL.md — this file is the historical
5
+ plan, not the onboarding path.
6
+ Last updated: v0.29.6 (header refresh). The milestones
7
+ below cover the v0.1.0–v0.7.0 scaffold era; later decisions live in CHANGELOG.md
8
+ (current through v0.29.6) and the current-state addendum in docs/DESIGN.md.
9
+
10
+ ---
11
+
12
+ ## 0. Product definition (frozen)
13
+
14
+ - **What it is**: a pi-coding-agent extension that supervises long-running work to *verified* completion.
15
+ - **Core mechanism**: a shared goal state machine + an `agent_end`-driven continuation loop + an **isolated auditor** (fresh pi session, no extensions, no skills, power-mode audit tools: read/grep/find/ls/bash) that must approve before a goal is marked complete.
16
+ - **Three loops on one machine**:
17
+ - **goal** — one ordered goal, audited (`/goal`)
18
+ - **list** — a queue of goals, each audited in turn (`/list`)
19
+ - **loop** — a forever-polish loop around a measurable target (`/loop`)
20
+ - **Naming is frozen**: commands are `/goal*`, `/list*`, `/loop*`. No `pi-gla-` prefix, no `oracle/sisyphus/squad/forge` metaphors anywhere (code, files, docs, keywords).
21
+
22
+ ### Non-goals (v0.x)
23
+
24
+ - No interop with `pi-goal-x` state (`.pi/goals/`). Clean break, `.pi-gla/` only.
25
+ - No web dashboard, no remote control, no multi-machine coordination.
26
+ - No planner/decomposer that invents the goal for the user (drafting *clarifies*; it does not originate).
27
+
28
+ ---
29
+
30
+ ## 1. Milestones & acceptance criteria
31
+
32
+ ### M0 — v0.1.0-alpha.1 scaffold ✅ (done)
33
+
34
+ - [x] Package layout, LICENSE, README, CHANGELOG, DESIGN, tsconfig
35
+ - [x] `extensions/loops/goal.ts` — commands + agent tools + agent_end loop
36
+ - [x] `extensions/goal-loop-core.ts` — types, JSONL ledger, markdown renderer
37
+ - [x] `extensions/goal-loop-auditor.ts` — isolated auditor session
38
+ - [x] `extensions/goal-loop-backoff.ts` — 5-min hard cap
39
+ - [x] `prompts/goal-loop-continuation.md`, `schemas/goal.schema.json`
40
+ - [x] 24 unit tests green (`npm test`)
41
+ - **Exit evidence**: `npm test` → 24/24 pass (verified 2026-07-20).
42
+
43
+ ### M1 — v0.1.0 (first real release)
44
+
45
+ Scope: make the goal loop actually work end-to-end in a live pi session. No new features.
46
+
47
+ - [ ] **Type-check clean**: `npm run check` (tsc --noEmit) → 0 errors.
48
+ - Known risk: `ExtensionContext`, `defineTool` import path, `pi.registerCommand` arg shapes were written against memory of pi-goal-x, not verified against the installed pi 0.74 API.
49
+ - [x] **Live smoke test** ✅ 2026-07-20 — full loop verified end-to-end in tmux: `/goal` → agent works → `complete_goal` → isolated auditor (opencode/deepseek-v4-flash-free, extension-less) approves → archived with clean 1-entry history + real auditor report.
50
+ - [x] **Fix whatever the smoke test breaks** ✅ — 6 real fixes: (1) API imports from public entrypoint + pi-ai/pi-agent-core types; (2) `sendMessage` on `pi` API not `ctx`; (3) stale-ctx crash → `lastCtx`/`rememberCtx` pattern; (4) `details:{}` in tool results, async handlers, `tool_call` event name; (5) auditor model default → `ctx.model` + string-ref resolver; (6) audit-history pollution — record only non-empty reports, cap at 20, include `error` field.
51
+ - [x] **Escape hatch verified** ✅ (with caveat) — Esc during audit aborts the pi turn; the auditor session may complete detached. Loop recovers cleanly via `agent_end` (verified live: 3 empty audits then approval). pi-goal-x's fancy Escape dialog is v0.2.0 scope. Abort signal is threaded into the auditor for when pi wires tool-level abort properly.
52
+ - [x] **Backoff cap verified** ✅ (incidentally, live) — openrouter 403 storm triggered exactly "Goal paused: 5 consecutive errors" auto-pause.
53
+ - [ ] Update CHANGELOG, tag `v0.1.0`, `npm publish`.
54
+
55
+ **Live smoke script** (target: < 5 min):
56
+ ```
57
+ pi -e /home/dracon/Dev/pi-goal-list-loop-audit
58
+ > /goal "Create file hello.txt containing the word world. Done when: grep -q world hello.txt"
59
+ # expect: agent writes file, calls complete_goal, auditor approves, goal archived
60
+ > /goal status # expect: complete, audit history shows 1 approved
61
+ cat .pi-gla/active.jsonl | tail -3
62
+ ls .pi-gla/archive/ # expect: one .md file
63
+ ```
64
+
65
+ ### M2 — v0.2.0 (list + drafting + regression_shield) ✅ (2026-07-20)
66
+
67
+ - [x] **Loop 2: `/list`** — `add|show|next|remove <n>|clear`; each item is a full goal; completing/aborting one auto-activates the next; session restart resumes a non-empty queue. Live-verified: two items auto-advanced through audit to archive.
68
+ - [x] **Drafting**: `/goal` no-args → agent grills one question at a time → `propose_goal_draft` → real Confirm dialog. Live-verified end-to-end (drafted goal completed with shield).
69
+ - [x] **regression_shield**: auditor must quote raw output per contract item in an `<evidence>` block; orchestrator converts evidence-free `<approved/>` into disapproval. Pure logic in `goal-loop-shield.ts`; 14 unit tests + live verification (verbatim `<evidence>` in history).
70
+ - [x] **Escape dialog**: abort → complete-without-audit / continue choice.
71
+ - [x] **Provider warning**: one-time `session_start` notice when the session provider isn't a confirmed built-in and no auditorModel is set. Live-verified on kilocode.
72
+ - [x] **Inline contract extraction**: one-liner `Done when:` now extracts (was silently skipped before — the shield never engaged on one-liners).
73
+ - [x] **Live integration harness**: `scripts/smoke.sh [goal|list|draft]` — goal scenario 5/5 assertions green.
74
+ - [x] CHANGELOG, version 0.2.0, publish.
75
+ - [ ] `max_subtasks_per_task` cap → moved to M3 (no task-list creation tool exists yet; capping nothing is premature).
76
+
77
+ ### M3 — v0.3.0 (loop) ✅ (2026-07-20) — design
78
+
79
+ **Loop 3 is metric-driven, not vibes-driven.** This is the anti-doorknob design:
80
+ pi-loop-mode's failure mode was endless "improvement" churn (the DOORKNOB problem).
81
+ Our loop only believes a number.
82
+
83
+ **Model**:
84
+ - User supplies: `target` (what to improve), `measure` (shell command that prints
85
+ a number), `direction` (min|max). Optional: `window` (plateau window, default 5),
86
+ `max` (iteration cap, default 50).
87
+ - On `/loop start`: orchestrator runs `measure` → baseline.
88
+ - On every `agent_end` while active: orchestrator runs `measure` → compare to best:
89
+ - improved (min: value < best; max: value > best) → new best, stall=0
90
+ - not improved / measure failed → stall++
91
+ - The **orchestrator** runs the measure (via `pi.exec`), never the agent —
92
+ the agent cannot fake the number.
93
+ - Stop conditions: `stall >= window` (plateau), `iteration >= max`, or `/loop stop`.
94
+ - No git-based auto-revert in v0.3.0 (too dangerous with uncommitted user work);
95
+ on regression the agent is instructed to undo its own last change, and the next
96
+ measure verifies.
97
+ - **No auditor in loop 3**: the metric IS the verdict. Documented.
98
+ - Mutual exclusion: a `/loop` cannot start while a goal/list is active and vice versa.
99
+
100
+ **Command shape**: `/loop start "<target>" measure="<cmd>" direction=min [window=5] [max=50]`
101
+ `/loop` (status) · `/loop stop`
102
+
103
+ **Collision note**: `/loop` collides with pi-loop-mode — the M1 collision detector
104
+ handles UX; smoke tests run under a bare `PI_CODING_AGENT_DIR` to isolate.
105
+
106
+ **Also in M3**:
107
+ - `propose_task_list` tool + `max_subtasks_per_task: 5` cap (M2 carry-over — makes
108
+ the existing complete_task/update_task_status tools actually usable).
109
+ - `notify=<cmd>` setting: shell out on goal complete / goal pause / loop stop
110
+ (message passed as `$1`; config-gated, no deps).
111
+ - Unit tests (metric parse, plateau logic, task cap) + `/loop` smoke scenario.
112
+
113
+ **M3 verification evidence** (all live, 2026-07-20):
114
+ - `/loop` smoke: metric 5→0 over 5 improving iterations (stall reset each time),
115
+ 3 stall iterations at 0, plateau stop at window=3, `loop_stopped` + per-iteration
116
+ `loop_measured` in ledger, notify fired on stop. `scripts/smoke.sh loop` 5/5.
117
+ - Regression check: `goal` 5/5, `list` 4/4, `draft` 3/3 — all scenarios hermetic
118
+ (bare agent dir + readiness wait) after two collision/REPL-race flakes.
119
+ - 73 unit tests green; `tsc --noEmit` clean.
120
+ - Found + fixed during M3: `/gla` whitespace split mangled quoted
121
+ notify commands; smoke `wait_for "plateau"` matched agent prose instead of
122
+ the orchestrator's stop text (assertions raced the loop).
123
+
124
+ ### M7 — v0.7.0 (global config tier) ✅ (2026-07-21)
125
+
126
+ User directive: settings are not per-goal/loop/list — there should be ONE
127
+ global config you set once and rarely open. Shipped: project > global >
128
+ defaults resolution, `/gla` writes global by default (`project`
129
+ prefix for local overrides), provenance display, 4 mergeSettings unit tests,
130
+ live-verified both tiers + no-leak smoke. Docs updated.
131
+
132
+ ### M6 — v0.6.0 (draft everything) ✅ (2026-07-20)
133
+
134
+ User directive: for a long-running thing, a draft up front is better. Drafting
135
+ exists only for `/goal`; `/list add` takes raw strings, and `/loop start`
136
+ demands a correct target+measure+direction in one blind shot — the most
137
+ expensive place to be wrong (up to 50 iterations before plateau stops a bad
138
+ metric). Draft all three loops; for `/loop`, validate the metric BEFORE
139
+ confirming.
140
+
141
+ 1. **Unified drafting modes**: drafting target becomes `"goal" | "list" |
142
+ "loop"`. `/goal` (existing), `/list add` with no args (draft → confirmed
143
+ contract goes into the QUEUE instead of activating), `/loop` with no args
144
+ (draft → confirmed loop config starts the loop).
145
+ 2. **`/loop` drafting with measure test-run** (centerpiece): the agent grills
146
+ about target + what number represents progress, then calls
147
+ `propose_loop_draft(target, measureCmd, direction, window?, max?)`. The
148
+ **orchestrator runs the measure command once** and shows target + measure +
149
+ real output + parsed number + direction in the Confirm dialog:
150
+ "`grep -c TODO src.txt` → `42` (min). Start?" A broken measure (no number)
151
+ is shown as such and the agent is told to fix the proposal. User validates
152
+ the metric before a single iteration burns tokens.
153
+ 3. **`/goals` archive browser**: list archived goals (id, status, stop reason,
154
+ objective head) from `.pi-gla/archive/`. Long-running tool needs history.
155
+ 4. Gates: unit tests (draft-mode routing, loop-draft measure parsing), smoke
156
+ scenarios for loop-drafting and list-drafting, publish v0.6.0.
157
+
158
+ **M6 evidence** (2026-07-20):
159
+ - Loop drafting live: agent located num.txt itself, proposed `cat num.txt`;
160
+ Confirm dialog showed the real test-run ("Parsed number: 10, lower is
161
+ better"); confirmed loop ran improving iterations immediately.
162
+ - List drafting live: confirmed contract → list_added → auto-activate →
163
+ audited → archived.
164
+ - `/goals` parsing verified against real archive entries.
165
+ - 89 unit tests, tsc clean.
166
+
167
+ **Still deferred**: live footer/TUI widget (now the ONLY remaining scoreboard
168
+ gap vs pi-loop-mode/pi-goal-x).
169
+
170
+ ### M5 — v0.5.0 (self-sufficiency) ✅ (2026-07-20)
171
+
172
+ User directive: a goal loop that dies silently after compaction and needs an
173
+ EXTERNAL plugin (`@badliveware/pi-compaction-continue`) to restart it is a hole
174
+ in OUR plugin. Liveness is the loop's own job. Bake it in; cut the watchdog.
175
+
176
+ 1. **Heartbeat self-watchdog** (replaces pi-compaction-continue for our loops):
177
+ a 15s interval checks: active goal-or-loop AND session idle AND no pending
178
+ continuation/loop timer AND no activity for 60s → re-fire the continuation.
179
+ One check covers every stall cause (compaction-eaten turn, dropped message,
180
+ stale ctx). Stall accounting: a heartbeat-nudged turn with ZERO tool calls
181
+ counts as a nudge; 3 consecutive → pause (mirrors the watchdog's 3-nudge cap,
182
+ but scoped to real goal progress). Pure decision function unit-tested.
183
+ Scope note: this covers stalls while a goal/loop is active. Non-goal sessions
184
+ are the user's own business — they are at the keyboard.
185
+ 2. **`/goal tweak "<text>"`** — edit the active goal's objective in place
186
+ (Confirm dialog shows old vs new; contract re-extracted from the new text).
187
+ Closes the last pi-goal-x feature gap we use.
188
+ 3. **Structured drafting forms**: drafting prompt prefers `ask_user_question`
189
+ (rpiv-ask-user-question) when the tool is available in the session — closes
190
+ the structured-forms gap vs pi-goal-x without a hard dependency.
191
+ 4. **Rig cuts** (after publish): `pi-codex-goal`, `pi-loop-mode`,
192
+ `@badliveware/pi-compaction-continue`. AGENTS.md stack table rewritten:
193
+ goal plane = pi-goal-list-loop-audit.
194
+
195
+ **M5 evidence** (2026-07-20):
196
+ - Heartbeat: 8 unit tests for the stall predicate + nudge accounting; `goal`
197
+ smoke 5/5 with the heartbeat interval live through the full cycle.
198
+ - `/goal tweak`: implemented with Confirm dialog + contract re-extraction.
199
+ - Drafting prompt prefers `ask_user_question` when available.
200
+ - 89 unit tests, tsc clean.
201
+
202
+ **Deferred**: live footer/TUI widget (pi-loop-mode's dashboard is the one thing
203
+ we genuinely lose by cutting it; v0.6.0 candidate if missed).
204
+
205
+ ### M4 — v0.4.0 (completion release) ✅ (2026-07-20)
206
+
207
+ Everything left, in one release. Completes the 6-flaw list and makes the docs honest.
208
+
209
+ 1. **Auditor compaction (flaw #3 — the LAST open flaw)**. Enable pi's built-in
210
+ compaction in the auditor session (currently `compaction: { enabled: false }`).
211
+ Safety argument: regression_shield is orchestrator-side — a compaction-degraded
212
+ auditor produces weaker evidence → disapproval, never false approval. The risky
213
+ direction (silent false approval) is structurally impossible.
214
+ 2. **Schema + examples + docs sync**. `schemas/goal.schema.json` still says "oracle"
215
+ and "v0.1.0 loop 1 only"; `examples/example-objective.md` used `/pi-gla-set`;
216
+ `tests/README.md` has stale counts; `docs/DESIGN.md` needs the v0.2/v0.3 addendum.
217
+ 3. **tokensUsed wiring + limit enforcement**. `AgentEndEvent.messages` carries
218
+ `usage.totalTokens` per assistant message — accumulate per goal. `tokensLimit`
219
+ becomes a real cost guard: crossing it pauses the goal with a clear reason
220
+ (configurable via `/glla tokenlimit=`).
221
+ 4. **Resumption notice** on `session_start`: if a goal is active or a loop is
222
+ running, say so. (The "plugin vanished" self-check from D4 is impossible from
223
+ inside the plugin — absent code cannot run. Recorded as rejected.)
224
+ 5. **Loop 3 git-branch mode** (`branch=1` flag): at `/loop start`, create scratch
225
+ branch `pi-glla-loop/<id>`; commit after each improving iteration; on regression
226
+ `git reset --hard` to the last improving commit ON THE SCRATCH BRANCH ONLY.
227
+ The user's branch and uncommitted work are never touched. Requires: git repo,
228
+ and we refuse `branch=1` with a dirty tree (refuse to mix user work into the
229
+ scratch branch).
230
+ 6. **Draft reject path** in the smoke harness (Confirm → No → agent refines).
231
+
232
+ After M4 the 6-flaw list is closed and the roadmap table is all-shipped.
233
+
234
+ **M4 verification evidence** (all live, 2026-07-20):
235
+ - Auditor compaction enabled; `goal` smoke 5/5 green after the change.
236
+ - Token guard: 3 unit tests for dedup accumulation; limit-pause path wired in
237
+ agent_end with settings-configurable budget.
238
+ - branch=1 live: 5 improvement commits on scratch branch, 0 for stalls, main
239
+ untouched, returned to main on plateau with merge instructions.
240
+ - `draft-reject` smoke 6/6: Confirm → reject → refine → Confirm → approval.
241
+ - Resumption notice on session_start for active goal/loop.
242
+ - 81 unit tests, tsc clean, all 5 smoke scenarios green.
243
+ - **6/6 pi-goal-x flaws now closed.** The D4 "plugin vanished" self-check is
244
+ recorded as REJECTED (absent code cannot run); replaced by the resumption
245
+ notice.
246
+
247
+ **Deferred to v0.4.0 (with justification)**: (superseded — this release)
248
+
249
+ ---
250
+
251
+ ## 2. Open decisions (must resolve before M1 publish)
252
+
253
+ ### D1 — Command collision strategy ✅ RESOLVED
254
+
255
+ **Verified in installed pi source** (`dist/core/extensions/runner.js:resolveRegisteredCommands`):
256
+ - Duplicate command names **never throw** and **never clobber** — both survive.
257
+ - First registrant keeps the bare name (`/goal`); later ones get `/goal:2`, `/goal:3`, …
258
+ - So the failure mode is degraded UX (our command reachable as `/goal:2`), never breakage.
259
+
260
+ **Decision: option 1 — plain names + detect-and-warn.** Implemented in `extensions/loops/goal.ts:warnOnCommandCollision`: at `session_start` we count registered command names via `pi.getCommands()`, and if any of ours (`goal`, `list`, `loop`, `goal-*`) appears more than once we notify the user with the degraded invocation name. Collision check is fail-silent (non-fatal by design).
261
+
262
+ ### D2 — Auditor model default ✅ RESOLVED (with a hard discovered constraint)
263
+
264
+ **Discovered during M1 smoke (2026-07-20): the auditor session has no extensions, so it can only use BUILT-IN providers.** On this rig the main session ran kilocode (`tencent/hy3:free`) — an extension-registered provider — and every auditor spawn failed with `No API key found for kilocode`. Verified bare-session matrix: `opencode/deepseek-v4-flash-free` works extension-less; kilocode/zenmux/kimi-coding do not.
265
+
266
+ **Decision**: default = session model (works when the session model is built-in); `/gla model=provider/id` overrides for rigs running extension-provided session models. The `/gla` save message now warns about the built-in-provider constraint. `resolveAuditorModel` documents it in code. v0.2.0 should add a startup check: if session model's provider is extension-registered and no auditorModel is set, warn once.
267
+
268
+ ### D3 — State dir name ✅ RESOLVED
269
+
270
+ **Keep `.pi-gla/`.** Internal-only path; renaming costs a migration for zero user-visible gain. If we ever regret it, the rename is a one-line constant (`piGlaDir` in `goal-loop-core.ts`) plus a migrate-on-read.
271
+
272
+ ### D4 — Persistence across pi updates ✅ RESOLVED
273
+
274
+ Known rig behavior (from earlier audits): `pi update` overwrites `~/.pi/agent/npm/node_modules/`, which can wipe npm-installed plugins. **Decision: document both install paths in INSTALL.md** — `pi install npm:pi-goal-list-loop-audit` (convenient, re-install after `pi update`) and project-local `.pi/extensions/` (permanent, survives updates). The `-e <path>` dev flow is unaffected. v0.2.0 should add a `session_start` self-check that notifies if the plugin vanished from the loaded set while `.pi-gla/active.jsonl` shows an active goal.
275
+
276
+ ---
277
+
278
+ ## 3. Verification gates (apply to every milestone)
279
+
280
+ A milestone is not done until:
281
+
282
+ 1. `npm test` green (unit).
283
+ 2. `npm run check` clean (types).
284
+ 3. Live smoke passes (M1+).
285
+ 4. CHANGELOG entry written.
286
+ 5. No `oracle|sisyphus|squad|forge|pi-gla-` string outside `.pi-gla/` dir name (run the grep).
287
+
288
+ ```bash
289
+ grep -rn "oracle\|sisyphus\|squad\|forge" \
290
+ tests/ extensions/ prompts/ docs/ examples/ README.md INSTALL.md CHANGELOG.md package.json \
291
+ | grep -v node_modules
292
+ # expect: no output
293
+ ```
294
+
295
+ ---
296
+
297
+ ## 4. Risks
298
+
299
+ | Risk | Likelihood | Mitigation |
300
+ |---|---|---|
301
+ | pi extension API drift (0.74 → next) | medium | pin peerDeps `*`; smoke test after every pi update |
302
+ | Command collision (D1) | high | resolve D1 before publish |
303
+ | Auditor cost (every complete_goal = extra session) | medium | D2 settings; document cost expectation in README |
304
+ | User installs alongside pi-goal-x and gets two loops fighting | medium | README "conflicts" section; loud notify if `.pi/goals/` detected |
305
+ | v0.1.0's auditor is rubber-stampable (`bash true`) until v0.2.0 regression_shield | known/accepted | documented in DESIGN + README; ship v0.2.0 fast |
306
+
307
+ ---
308
+
309
+ ## 5. Publish checklist (M1)
310
+
311
+ - [ ] D1–D4 resolved and recorded in this file
312
+ - [ ] `npm test` + `npm run check` + live smoke all green
313
+ - [ ] Version bump `0.1.0-alpha.1` → `0.1.0`
314
+ - [ ] git init + initial commit + GitHub repo `dracon/pi-goal-list-loop-audit`
315
+ - [ ] `npm publish --access public`
316
+ - [ ] Verify: `pi install npm:pi-goal-list-loop-audit` on a clean rig
package/README.md CHANGED
@@ -8,9 +8,9 @@ The auditor runs in a fresh extension-less pi RPC process with no extensions, sk
8
8
 
9
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.
10
10
 
11
- On Windows, npm installs the `pi.cmd` shim rather than a directly executable `pi` binary. The auditor launches it through an explicitly quoted `cmd.exe` boundary; POSIX keeps direct shell-less execution. Protocol snapshots also tolerate transient Windows file-locks without deleting the last valid snapshot first.
11
+ On Windows, npm installs the `pi.cmd` shim rather than a directly executable `pi` binary. The auditor launches it through an explicit `cmd.exe` boundary; arguments are quoted only when tokenization requires it (v0.35.27 — quoting a bare executable name breaks `.CMD` shim resolution on pnpm installs), and every argument passes the unsafe-character gate (`%`, CR, LF) before that decision. POSIX keeps direct shell-less execution. Protocol snapshots also tolerate transient Windows file-locks without deleting the last valid snapshot first.
12
12
 
13
- **Current package version:** `v0.35.13` — use `/glla version` to see the installed version and the command for comparing it with the registry latest. This checkout may contain unreleased changes; the npm registry is authoritative for published versions.
13
+ **Current package version:** `v0.35.32` — use `/glla version` to see the installed version and the command for comparing it with the registry latest. This checkout may contain unreleased changes; the npm registry is authoritative for published versions.
14
14
 
15
15
  ## Why this exists
16
16
 
@@ -53,7 +53,7 @@ Five top-level commands — `/goal`, `/list`, `/loop`, `/glla`, `/review`:
53
53
  /goal verify # queue a detached auditor for the current goal — no agent turn (v0.28.27, renamed from /goal audit in v0.29.8)
54
54
  /goal tweak "<new objective>" # edit in place (Confirm dialog)
55
55
  /goal archive # archived goals, newest first
56
- /glla # settings UI table · actions include /glla version · /glla status · /glla stats · /glla audits [N|full] · /glla cancel (cancel the active objective) · /glla postaudit · /glla wipe (idempotent all-live-state reset, Confirm-gated)
56
+ /glla # settings UI table · actions include /glla version · /glla status · /glla stats · /glla audits [N|full] · /glla agents (tracked-subagent panel; --tail <id> reads a child transcript read-only) · /glla pause (freeze ALL supervisor automation — active work keeps running) · /glla cancel (cancel the active objective) · /glla postaudit · /glla wipe (idempotent all-live-state reset, Confirm-gated)
57
57
  /list fix the login bug, add dark mode, write docs # dump it — the agent shapes it into items, one Confirm
58
58
  /list plan.md # file detected → bulk import, one Confirm (sisyphus/Ralph style)
59
59
  /list <paste a checklist> # multi-line paste → same batch flow
@@ -240,7 +240,7 @@ Each loop is a different policy class on the same status machine.
240
240
  | Flaw in pi-goal-x | Fix in pi-goal-list-loop-audit |
241
241
  |---|---|
242
242
  | `detailedSummary` is hand-concat strings | Structured JSON state + native markdown renderer |
243
- | Stuck-counter has no ceiling — 1-hour waits happen | Hard 5-minute backoff cap, fall through to user notification |
243
+ | Stuck-counter has no ceiling — 1-hour waits happen | Bounded retry envelope: eager 5s first retry, then the hourly-aligned ladder (v0.35.0); stall ladder + heartbeat nudges cap silent waits |
244
244
  | 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 |
245
245
  | `pause_goal` is fire-and-forget | Clear `pauseReason` surfaced in status + agent feedback |
246
246
  | Vague objective + weak auditor = rubber-stamp | Drafting phase with Confirm dialog + isolated auditor + shield |
@@ -286,6 +286,29 @@ tool call or hidden reasoning interval therefore remains visibly timed; after
286
286
  three minutes without worker activity the UI changes to `auditor quiet` and
287
287
  names the cancellation/recovery path instead of presenting a frozen live card.
288
288
 
289
+ **Per-phase glyphs + activity meter (v0.35.15).** Every auditor phase carries a
290
+ distinct glyph — `⋯` queued, `▶` running, `◌` quiet, `⛔` blocked, `✓`
291
+ awaiting-verdict — beside a draining `▰▱` activity meter, with the dense text
292
+ kept as secondary detail. When a quiet stretch ends, the footer summarizes it
293
+ (`silent 8m then resumed`) so silence is reported, not just survived. A single
294
+ proactive warning fires when the detached auditor crosses the quiet threshold;
295
+ it never repeats per tick.
296
+
297
+ **Supervisor freeze (v0.35.15).** `/glla pause` silences every automatic
298
+ side-effect — heartbeat re-arms, recovery probes, auto-resume, auto-continuation
299
+ dispatch, the proactive quiet notify, and (v0.35.17) the zero-stream auto-retry
300
+ below — without touching active work or a running detached audit. The flag is
301
+ persisted and survives restarts; `/glla resume` clears it. Bare `/glla` shows
302
+ the frozen state.
303
+
304
+ **Zombie watchdog vs subagent waits (v0.35.26, issue #13).** A parent
305
+ blocked on a foreground subagent call is stream-silent by design, so the
306
+ zero-stream watchdog stands down while one is in flight. The recognized
307
+ names cover both the built-ins (`Agent`, `get_subagent_result`,
308
+ `steer_subagent`) and the pi-subagents extension's registrations
309
+ (`subagent`, `subagent_wait`), shared by the watchdog and the wedge-alert
310
+ hint so they cannot drift apart again.
311
+
289
312
  ## Provider failures: aggressive retry envelope, bounded (v0.35.0)
290
313
 
291
314
  Error text is **not trusted** to pick a retry policy. The runtime does not
@@ -299,6 +322,9 @@ adds a blind `:00:30` retry after each hour starts, so work can be picked up
299
322
  quickly after a possible provider-side change. The automatic window is 24h;
300
323
  explicit `/goal resume`, `/list resume`, or `/loop resume` starts a fresh
301
324
  window. With global `autoResume=on`, pending retries survive a session reload.
325
+ A loop parked by the zero-stream abort (v0.35.25, issue #14) is explicitly
326
+ resumable: `/loop resume` re-arms it with the preserved iteration count,
327
+ best value, and history — exactly as the abort message promises.
302
328
 
303
329
  Only failures identified by positive evidence as futile avoid automatic retry:
304
330
  context/output-token limits and user aborts (`non-recoverable`). Auditor
@@ -370,6 +396,16 @@ brake streak, so a broken provider can't spin forever. A confirmed queued
370
396
  continuation with no turn is reported by the queue-stuck probe; it does not
371
397
  inject terminal input.
372
398
 
399
+ **Zero-stream zombie abort + one bounded auto-retry (v0.35.17).** When pi stays
400
+ BUSY with zero provider stream activity for 20 minutes, glla warns; after a
401
+ 10-minute grace it aborts the zombie turn and parks the work safely. Since
402
+ v0.35.17 the FIRST such silence arms exactly ONE automatic retry ~90 seconds
403
+ later (the park becomes a waystation, not a dead end — field: turns dispatched
404
+ by accepting Confirm dialogs hung this way repeatedly). If the retry also hangs,
405
+ the second consecutive silence parks permanently for manual `/goal resume` /
406
+ `/list resume`. `/glla pause` freezes the retry like every other automatic
407
+ side-effect.
408
+
373
409
  ## Session replacement and stale handles
374
410
 
375
411
  Recovery crosses pi's lifecycle boundary. On `session_shutdown`, glla records
@@ -423,6 +459,37 @@ loser is archived (recoverable under `.pi-glla/archive/`), never silently
423
459
  wiped. Legacy `complete`/`aborted` terminal slots are also cleared once their
424
460
  archive exists, while the final summary remains available in history.
425
461
 
462
+ ### Load without autostart (v0.35.23)
463
+
464
+ On startup glla RESTORES and DISPLAYS all durable state — active/paused
465
+ goal, waiting queue, loop — but holds every automatic dispatch until you
466
+ decide. The load hold freezes the same machinery as `/glla pause`
467
+ (continuation dispatch, loop ticks, heartbeat refires, recovery timers)
468
+ through one shared gate; unlike a manual pause it keeps host-loss
469
+ supervision probing, and it is released by any explicit work command:
470
+ `/goal resume`, `/list resume`, `/list next`, `/loop resume`, `/loop start`,
471
+ or starting a new goal. Every release is ledgered (`load_hold_engaged` /
472
+ `load_hold_released`). Set global **Auto-resume = on** to restore
473
+ load-time automation for unattended rigs — the consent is the raw setting,
474
+ not the aggressive-mode default. Narrow continuity exceptions keep working
475
+ without consent: validated handoffs/rebinds, same-process session
476
+ successors, re-arming of work already in flight when a host silently died,
477
+ and the single retry a parked completion claim earns when main-model
478
+ recovery heals the provider that parked it.
479
+
480
+ **Due-wait backstop (v0.35.28, issue #16).** A time-gated wait pause
481
+ (`pauseKind: "wait"` with a `pauseResumeAt`) is no longer trusted to
482
+ in-memory timers alone — agent-authored waits armed none, error-brake
483
+ cooldowns were not re-armed on reload, and every scheduled resume died with
484
+ its session. The heartbeat now compares wall time against `pauseResumeAt`
485
+ every tick and re-fires the route once the deadline lapses by more than
486
+ ~90s (main-model waits probe the provider; other waits clear the park and
487
+ dispatch one fresh continuation). `/glla pause` and the load hold still
488
+ freeze it; every fire is ledgered (`wait_pause_overdue_resume`). Auto-resumed
489
+ goals carry a RECOVERY NOTICE in their next continuation prompt — "welcome
490
+ back, YOU were recovered" — so the agent continues its own work instead of
491
+ waiting for an external recovery signal that already fired.
492
+
426
493
  ## Completion and destructive commands
427
494
 
428
495
  An approved objective writes its final completion summary to the archive and
@@ -442,6 +509,17 @@ Open `/glla` to edit these settings in the table (the rows show effective values
442
509
 
443
510
  - Auditor model and thinking level
444
511
  - Auditor fallback agent
512
+
513
+ **Auditor selection (v0.35.24):** the **Auditor model** row opens the same
514
+ `/model`-style fuzzy picker the main agent flows use — configured-auth models
515
+ only, with a session-model row and a typed escape hatch. It is at full parity
516
+ with the main selector on policy too: your forbidden-models patterns filter
517
+ the picker list AND a typed match is refused with a named warning, so a pin
518
+ saved here is one `resolveAuditorModel` will actually honor. The pick lands
519
+ in global `auditorModel` and is followed immediately by the auditor thinking
520
+ dialog for that model. The **Auditor fallback agent** row applies the same
521
+ filtering to the failure-over pin.
522
+
445
523
  - Notify command, token limit, and wedge-alert minutes
446
524
  - Auto-resume, auto-accept drafts, decision popup, and carryover policy
447
525
  - Main-agent current model/thinking, fallback models, recovery cadence, and preferred-primary failback policy in the Main agent tab
@@ -452,11 +530,14 @@ Open `/glla` to edit these settings in the table (the rows show effective values
452
530
  stall brakes
453
531
 
454
532
  The argument namespace is reserved for actions such as `/glla status`, `/glla
455
- resume`, `/glla cancel`, `/glla stats`, `/glla audits`, `/glla tooloverride`,
456
- `/glla fallbacks clear`, and `/glla wipe`. `fallbacks clear` atomically removes
457
- the global main-agent fallback chain and cancels any pending fallback switch. Cancel stops the
458
- active objective; wipe clears all live state while preserving history.
459
- There is no top-level `/glla key=value` setting syntax.
533
+ pause`, `/glla resume`, `/glla cancel`, `/glla stats`, `/glla audits`,
534
+ `/glla tooloverride`, `/glla fallbacks clear`, and `/glla wipe`. `fallbacks clear`
535
+ atomically removes the global main-agent fallback chain and cancels any pending
536
+ fallback switch. Pause freezes every automatic supervisor side-effect (heartbeat
537
+ re-arms, recovery probes, auto-resume, continuation dispatch, loop ticks, quiet
538
+ notifications) without touching active work, and survives session restarts;
539
+ resume unfreezes. Cancel stops the active objective; wipe clears all live state
540
+ while preserving history. There is no top-level `/glla key=value` setting syntax.
460
541
 
461
542
  Resolution per key: **project > global > defaults** — EXCEPT `autoResume` and
462
543
  agent recovery settings (`mainModelFallbacks`, `mainModelRetryMinutes`,
@@ -598,23 +679,37 @@ customizes.
598
679
 
599
680
  ## Files
600
681
 
682
+ Post-decomposition layout (the v0.34.x monolith is gone — `loops/goal.ts` is
683
+ a thin activation/wiring installer):
684
+
601
685
  ```
602
686
  extensions/
603
- loops/goal.ts # /goal + /list commands, agent tools, loop driver
687
+ goal-commands.ts # /goal + /list command surface, drafting, wipe/stats
688
+ loops/goal.ts # public activation/wiring installer (thin)
689
+ loops/goal-tools.ts # agent tools (complete_goal, pause_goal, list_*, loop drafts)
690
+ loops/goal-orchestrator.ts # goal lifecycle: create/archive/advance, reviewer
691
+ loops/goal-auditor-hooks.ts # completion-audit claim/recovery machinery
692
+ loops/goal-activation.ts # event wiring, command registration, session lifecycle
693
+ loops/goal-settings-ui.ts # settings editors + model pickers
604
694
  goal-loop-core.ts # types, JSONL state, pure helpers
605
695
  goal-loop-auditor.ts # auditor prompt + legacy in-process helper
606
696
  goal-loop-auditor-process.ts # detached worker protocol + shield revalidation
607
697
  goal-loop-shield.ts # regression_shield (pure, dependency-free)
608
- goal-loop-display.ts # status line + /goal status rendering
698
+ goal-loop-display.ts # widget/status rendering (incl. last-outcome retention)
699
+ goal-heartbeat.ts # heartbeat self-watchdog, subagent probes, due-wait backstop
700
+ goal-continuation.ts # continuation scheduling/dispatch + prompts
701
+ goal-recovery.ts # main-model recovery + completion-audit recovery
702
+ goal-loop.ts # Loop 3 machinery: /loop tick engine, git finish
609
703
  goal-loop-forever.ts # /loop measure/parse/plateau helpers
610
- goal-loop-backoff.ts # 5-min hard cap
704
+ goal-loop-backoff.ts # scheduling constants + stall/wedge/pending-latch decisions
611
705
  prompts/
612
- goal-loop-continuation.md # loop driver prompt
706
+ goal-loop-continuation.md # continuation prompt
613
707
  goal-loop-draft.md # drafting prompt
614
708
  goal-loop-forever.md # /loop driver prompt
615
709
  goal-loop-forever-draft.md # /loop drafting prompt
616
710
  scripts/
617
711
  goal-auditor-worker.mjs # extension-less RPC auditor child process
712
+ goal-auditor-launch.mjs # Windows-safe spawn spec builder (gate-before-quote)
618
713
  smoke.sh # live integration harness (tmux + real models)
619
714
  tests/ # current test count is reported by `bun test`; no live pi required for the suite
620
715
  docs/DESIGN.md # architectural decisions
@@ -0,0 +1,76 @@
1
+ # Design — subagent visibility (`/glla agents`, issue #15)
2
+
3
+ Status: SCOPE AGREED with the user 2026-08-22 (panel + transcript tail +
4
+ widget line; live activity stream explicitly rejected as too noisy).
5
+ This document is the implementation contract for the follow-up work.
6
+
7
+ ## Problem (issue #15)
8
+
9
+ During long fan-outs the only child visibility is the widget's 3-slot
10
+ "recent actions" ring. A child that "almost completed its final report,
11
+ went back to check some more, then crashed" is invisible: the parent sees
12
+ a silent wait, the user sees nothing actionable, and post-mortem evidence
13
+ lives in files nobody knows how to find.
14
+
15
+ ## Agreed scope
16
+
17
+ ### 1. `/glla agents` — snapshot panel
18
+
19
+ One-shot table of every tracked subagent, sourced from what glla already
20
+ holds (no new instrumentation):
21
+
22
+ - `subagentHangProbes` (goal-heartbeat.ts): agentType, summary, spawnedAt,
23
+ lastProgressAt, toolUses, outputTokens, endedAt, hangAlertedAt.
24
+ - `subagentManagerPoller()` when pi-subagents publishes its registry
25
+ (absent on some installed versions — always degrade gracefully to
26
+ event-derived evidence).
27
+ - `flags.inFlightToolCalls` for which parent wait (foreground Agent /
28
+ subagent call) each running child blocks.
29
+ - Ledger history of `subagent_hang_detected` for the "Recent hangs" footer
30
+ of the panel.
31
+
32
+ Row shape:
33
+
34
+ ```
35
+ ● explore map-model-picker RUNNING 4m12s tools 18 · out 2.1k · silent 0m
36
+ ● plan audit-contract HUNG? 31m tools 6 → frozen · out 890 · silent 26m
37
+ └ blocks: foreground subagent call (zombie stand-down active)
38
+ ✓ explore schema-check ENDED ok 3m44s
39
+ ```
40
+
41
+ Hung classification reuses `classifyHungSubagents` semantics (record-frozen
42
+ vs event-only evidence). Cap display at ~20 rows; prune ended probes per
43
+ the existing SUBAGENT_HANG_PRUNE_MS rule.
44
+
45
+ ### 2. `/glla agents --tail <id>` — child transcript tail (post-mortem)
46
+
47
+ Locate the child's session file on disk (pi sessions are JSONL under the
48
+ session store; pi-subagents records expose/allow correlation by id — probe
49
+ both the manager record and the probe registry) and print the LAST N lines
50
+ (N default 20, `--lines` override) rendered as `[tool] …/[asst] …/[user] …`
51
+ with truncation. If the file cannot be located, say so LOUDLY and name the
52
+ searched paths — never silently print an empty tail. Read-only: the tail
53
+ NEVER resumes or attaches to the child session.
54
+
55
+ ### 3. Widget line — ambient awareness
56
+
57
+ One footer segment while children are tracked: `● N agents · <busiest>
58
+ silent Xm ⚠` (⚠ only past the hang threshold). Reuses the existing widget
59
+ render path in goal-loop-display/goal-ui; hidden when zero tracked
60
+ children so idle rigs see no change.
61
+
62
+ ## Non-goals (explicitly rejected with the user)
63
+
64
+ - Live streaming of child tool calls into the main transcript (noise).
65
+ - Any attach/resume capability from the panel (read-only by design).
66
+ - New cross-extension contracts beyond the existing defensive manager poll.
67
+
68
+ ## Implementation notes
69
+
70
+ - New module `extensions/goal-agents-panel.ts` (pure render functions +
71
+ data assembly), wired into the `/glla` argument namespace next to
72
+ `/glla audits`; widget segment in goal-ui.
73
+ - All rendering pure/testable: feed fixtures of probes + manager records;
74
+ pin hung classification, cap behavior, loud-missing-file behavior for
75
+ --tail, and widget hide-at-zero.
76
+ - Version + CHANGELOG + README at ship time; full release gate.