pi-goal-list-loop-audit 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +252 -0
- package/docs/DESIGN.md +214 -0
- package/extensions/goal-loop-auditor.ts +391 -0
- package/extensions/goal-loop-backoff.ts +99 -0
- package/extensions/goal-loop-core.ts +506 -0
- package/extensions/goal-loop-display.ts +160 -0
- package/extensions/goal-loop-forever.ts +230 -0
- package/extensions/goal-loop-shield.ts +59 -0
- package/extensions/loops/goal.ts +2323 -0
- package/package.json +66 -0
- package/prompts/goal-loop-continuation.md +83 -0
- package/prompts/goal-loop-draft.md +39 -0
- package/prompts/goal-loop-forever-draft.md +50 -0
- package/prompts/goal-loop-forever.md +46 -0
- package/schemas/goal.schema.json +98 -0
- package/scripts/smoke.sh +210 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dracon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# pi-goal-list-loop-audit
|
|
2
|
+
|
|
3
|
+
> **Goal. Loop. Audit. Done.**
|
|
4
|
+
|
|
5
|
+
A pi-coding-agent extension that supervises long-running work to verified completion. The plugin 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.
|
|
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.
|
|
8
|
+
|
|
9
|
+
## Why this exists
|
|
10
|
+
|
|
11
|
+
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
|
+
|
|
13
|
+
`pi-goal-list-loop-audit` separates **implementation** from **verification**. Two independent sessions, two independent read paths, two perspectives.
|
|
14
|
+
|
|
15
|
+
### Architectural guarantee
|
|
16
|
+
|
|
17
|
+
| Stage | Protection |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Goal intake | Drafting + Confirm/Reject dialog; nothing activates unconfirmed |
|
|
20
|
+
| 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 |
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
Install:
|
|
26
|
+
```bash
|
|
27
|
+
pi install npm:pi-goal-list-loop-audit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Four top-level commands, that's all:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
/goal # drafting: agent grills, you Confirm
|
|
34
|
+
/goal "audit the repo" # no contract clause → agent grills you first (propose is gated on it)
|
|
35
|
+
/goal "Step 1. Step 2. Done when: tests pass." # has contract → starts now
|
|
36
|
+
/goal status # show state
|
|
37
|
+
/goal pause # pause
|
|
38
|
+
/goal resume # resume
|
|
39
|
+
/goal cancel # abort
|
|
40
|
+
/goal tweak "<new objective>" # edit in place (Confirm dialog)
|
|
41
|
+
/goal archive # archived goals, newest first
|
|
42
|
+
/gla # open the settings UI (or /gla key=value)
|
|
43
|
+
/list add # draft a contract (or a whole batch via items[])
|
|
44
|
+
/list add "<objective>" # queue one directly
|
|
45
|
+
/list add plan.md # file detected → bulk import, one Confirm
|
|
46
|
+
/list add <paste a checklist> # multi-line paste → same batch flow
|
|
47
|
+
|
|
48
|
+
(Or just say it: "queue these 10 things…" — the agent manages the list too.)
|
|
49
|
+
|
|
50
|
+
**Order is the default, not the law**: auto-advance takes the head (FIFO), but
|
|
51
|
+
`/list next <n>` or the agent's `list_activate` tool picks any item — with
|
|
52
|
+
subagents, what gets worked next is a choice, not a position. Numbering always
|
|
53
|
+
matches `/list show`.
|
|
54
|
+
/list # show active + queue
|
|
55
|
+
/list next # skip current, activate next
|
|
56
|
+
/list remove <n> # drop item n from the queue
|
|
57
|
+
/list clear # empty the queue
|
|
58
|
+
/loop # draft the loop (agent grills; measure is test-run before you confirm)
|
|
59
|
+
/loop start "reduce TODOs" measure="grep -c TODO src.txt | head -1" direction=min
|
|
60
|
+
/loop start "shrink the bundle" measure="..." direction=min time=4 tokens=500000 # arbitrary bounds
|
|
61
|
+
/loop start "reduce TODOs" measure="..." direction=min branch=1 # scratch-branch mode
|
|
62
|
+
/loop status # iteration, best, stall, recent values
|
|
63
|
+
/loop stop # halt with summary
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Subcommands match **exactly** — `/goal pause the pipeline` sets an objective
|
|
67
|
+
about a pipeline; only bare `/goal pause` pauses. (Same rule everywhere, so
|
|
68
|
+
your objectives can start with any verb.)
|
|
69
|
+
|
|
70
|
+
Drafting rules: **no-args drafts, args-without-a-`Done when:`-clause get
|
|
71
|
+
grilled by the agent (proposing is mechanically blocked until you have
|
|
72
|
+
replied at least once), args-with-a-clause start instantly, a file path is
|
|
73
|
+
bulk direct.** A
|
|
74
|
+
sisyphus-style plan file (checklists, bullets, numbered, plain lines) imports
|
|
75
|
+
as-is — headings become nothing, items become goals. And the drafter itself
|
|
76
|
+
batches: asking for "these 50 tasks" in a `/list` drafting session produces
|
|
77
|
+
ONE confirmed batch, not 50 dialogs.
|
|
78
|
+
Note: every queue item is audited individually, so at hundreds of items the
|
|
79
|
+
audit cost per item is the thing to think about.
|
|
80
|
+
|
|
81
|
+
**Drafting is the default for long-running things.** `/goal`, `/list add`, and
|
|
82
|
+
`/loop` with no arguments all start a grilling turn that ends in a Confirm
|
|
83
|
+
dialog. For `/loop` specifically, the orchestrator **test-runs the proposed
|
|
84
|
+
measure command once** and shows the real number in the dialog — you validate
|
|
85
|
+
the metric before a single iteration burns tokens.
|
|
86
|
+
|
|
87
|
+
With `branch=1`, all work lands on a scratch branch (`pi-gla-loop/<ts>-<slug>`):
|
|
88
|
+
improvements are committed, regressions are hard-reset (scratch branch only),
|
|
89
|
+
and on stop you return to your original branch with merge instructions.
|
|
90
|
+
Requires a clean working tree.
|
|
91
|
+
|
|
92
|
+
Loop 3 is metric-driven: the **orchestrator** runs your `measure` command after
|
|
93
|
+
every agent turn. The agent never self-reports progress — the loop only
|
|
94
|
+
believes a number. There is no auditor in loop 3; the metric is the verdict.
|
|
95
|
+
|
|
96
|
+
**A loop never completes.** Goal = achievement, loop = process: there is no
|
|
97
|
+
`done=` (v0.15.0 removed it — "improve until X" is a `/goal`). A loop runs
|
|
98
|
+
until `/loop stop`, plateau (`window=5` non-improving iterations — the well is
|
|
99
|
+
dry, not "done"), `max=` iterations, or the arbitrary bounds `time=<hours>` /
|
|
100
|
+
`tokens=<budget>`. And the spec is **alive**: mid-loop the agent can call
|
|
101
|
+
`propose_loop_refine` to sharpen the target or swap the measure — you confirm,
|
|
102
|
+
the orchestrator test-runs and re-baselines, and both eras stay in history.
|
|
103
|
+
|
|
104
|
+
## Which loop? (the decision rule)
|
|
105
|
+
|
|
106
|
+
**`/goal`** — one thing, judged *semantically*. Research, features, docs,
|
|
107
|
+
anything where "done" needs a reader. The isolated auditor verifies against
|
|
108
|
+
your `Done when:` contract with quoted evidence.
|
|
109
|
+
|
|
110
|
+
**`/list`** — many things, judged the same way, in turn. Bulk-import a plan
|
|
111
|
+
or just say "queue these 10 things". Order is the default, not the law:
|
|
112
|
+
`/list next <n>` picks any item.
|
|
113
|
+
|
|
114
|
+
**`/loop`** — one thing, judged *numerically*, as a **process that never
|
|
115
|
+
completes**. ONLY when a shell command can print a number that honestly
|
|
116
|
+
tracks progress: test failures, TODO count, bundle size, coverage %, lint
|
|
117
|
+
warnings, build time, dep count. The metric IS the auditor here — there is
|
|
118
|
+
no semantic judge, so a fake metric (word count, file exists) is worse than
|
|
119
|
+
no loop. There is no finish line (`done=` was removed in v0.15.0 — "improve
|
|
120
|
+
until X" is a `/goal`); the loop runs until you stop it, the metric plateaus,
|
|
121
|
+
or a time/token bound trips. `/loop` with no args drafts one for you:
|
|
122
|
+
the agent proposes a measure, the orchestrator **test-runs it and shows you
|
|
123
|
+
the real number** before you confirm; if no honest metric exists it will
|
|
124
|
+
redirect you to `/goal`.
|
|
125
|
+
|
|
126
|
+
## Three loops on one state machine
|
|
127
|
+
|
|
128
|
+
| Loop | Command | Status |
|
|
129
|
+
|---|---|---|
|
|
130
|
+
| 1. Single ordered goal | `/goal "<objective>"` | **shipped v0.1.0** |
|
|
131
|
+
| 2. Queue of goals | `/list add\|show\|next\|remove\|clear` | **shipped v0.2.0** |
|
|
132
|
+
| 3. Forever-polish loop | `/loop start\|status\|stop` | **shipped v0.3.0** |
|
|
133
|
+
|
|
134
|
+
Each loop is a different policy class on the same status machine.
|
|
135
|
+
|
|
136
|
+
## What this fixes vs. pi-goal-x
|
|
137
|
+
|
|
138
|
+
| Flaw in pi-goal-x | Fix in pi-goal-list-loop-audit |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `detailedSummary` is hand-concat strings | Structured JSON state + native markdown renderer |
|
|
141
|
+
| Stuck-counter has no ceiling — 1-hour waits happen | Hard 5-minute backoff cap, fall through to user notification |
|
|
142
|
+
| 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 |
|
|
143
|
+
| `pause_goal` is fire-and-forget | Clear `pauseReason` surfaced in status + agent feedback |
|
|
144
|
+
| Vague objective + weak auditor = rubber-stamp | Drafting phase with Confirm dialog + isolated auditor + shield |
|
|
145
|
+
| Esc mid-audit just dies | Escape dialog: complete-without-audit / continue (shipped v0.2.0) |
|
|
146
|
+
| Auditor can't compact — context exhaustion mid-audit | Compaction enabled (v0.4.0); safe because the shield is orchestrator-side |
|
|
147
|
+
| Agent can grow subtasks indefinitely | `propose_task_list` with 20/5 caps + Confirm dialog (v0.3.0) |
|
|
148
|
+
|
|
149
|
+
## Live TUI (always know it's on)
|
|
150
|
+
|
|
151
|
+
A persistent `gla:` status segment + an above-editor widget show the current
|
|
152
|
+
goal/loop at all times: objective, status, elapsed, tokens, next task or loop
|
|
153
|
+
metric, pause reason, and live auditor progress during audits. If something is
|
|
154
|
+
running, you can see it — no command needed.
|
|
155
|
+
|
|
156
|
+
## Self-watchdog (liveness is built in)
|
|
157
|
+
|
|
158
|
+
A 15s heartbeat detects the precise stall condition — active goal/loop + idle
|
|
159
|
+
session + nothing scheduled + quiet for 60s — and re-fires the continuation
|
|
160
|
+
itself. Three consecutive zero-tool turns pause the goal / stop the loop.
|
|
161
|
+
No external watchdog plugin needed.
|
|
162
|
+
|
|
163
|
+
## Config (one global place, rarely opened)
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
/gla # open the settings UI
|
|
167
|
+
/gla model=provider/id # auditor model override → GLOBAL
|
|
168
|
+
/gla thinking=high # auditor thinking → GLOBAL
|
|
169
|
+
/gla notify='cmd "$1"' # push on complete/pause/stop → GLOBAL
|
|
170
|
+
/gla tokenlimit=10000000 # per-goal token budget (default: off) → GLOBAL
|
|
171
|
+
/gla tokenlimit=0 # explicitly no cap (the default)
|
|
172
|
+
/gla project tokenlimit=500 # rare per-project override
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Resolution per key: **project > global > defaults**. The auditor defaults to
|
|
176
|
+
your pi session model. When the session provider is extension-registered the
|
|
177
|
+
auditor can't auth it — you're told once (info level) with the fix:
|
|
178
|
+
`/gla model=provider/id`, set once, rarely touched again. The plugin never
|
|
179
|
+
picks a model itself. Thinking follows the session too (floor `high`).
|
|
180
|
+
|
|
181
|
+
## Token guard
|
|
182
|
+
|
|
183
|
+
Every goal tracks real token usage; crossing the budget pauses the goal.
|
|
184
|
+
Default 10,000,000 per goal — a runaway threshold, not a big-goal threshold
|
|
185
|
+
(real research/feature goals legitimately burn 2-4M). Tune with
|
|
186
|
+
`/gla tokenlimit=<n>`. Loop 3 doesn't need this cap — it has its own brakes
|
|
187
|
+
(max iterations + plateau).
|
|
188
|
+
|
|
189
|
+
## Compatibility (what goes well, what conflicts)
|
|
190
|
+
|
|
191
|
+
**The Two-Driver Rule**: any plugin that drives agent turns on `agent_end`
|
|
192
|
+
conflicts — two supervisors scheduling continuations into one session produce
|
|
193
|
+
contradictory turns. One driver at a time:
|
|
194
|
+
|
|
195
|
+
- **Hard conflicts** (do not install together): `pi-codex-goal`, `pi-loop-mode`,
|
|
196
|
+
`pi-goal-x`, `pi-goal*`, `ralphi`, `pi-ralph*`, `pi-autoresearch` (active).
|
|
197
|
+
- **Overlap**: `@badliveware/pi-compaction-continue` — our heartbeat covers
|
|
198
|
+
stalls while a goal/list/loop is active; both installed may double-nudge.
|
|
199
|
+
- **Installed-but-don't-run-simultaneously**: `@tmustier/pi-ralph-wiggum` —
|
|
200
|
+
fine to keep, never run a ralph loop while a goal/list/loop is active.
|
|
201
|
+
|
|
202
|
+
**Goes well with it**: `@juicesharp/rpiv-ask-user-question` (drafting uses its
|
|
203
|
+
structured forms), `@tintinweb/pi-subagents` (spawn research/review subagents
|
|
204
|
+
inside goal work), `@tintinweb/pi-tasks` (session-wide DAGs vs our goal-scoped
|
|
205
|
+
task lists — different granularity), `pi-chrome` (the research/search path for
|
|
206
|
+
goals — logged-in browsing with no extra services; standalone search skills
|
|
207
|
+
like `mmx-cli`/`pi-search-skill` are optional conveniences for bulk queries,
|
|
208
|
+
not requirements).
|
|
209
|
+
|
|
210
|
+
**Two footnotes**: (1) extension-registered providers work in the main session
|
|
211
|
+
but not the auditor's extension-less session — if audits fail auth, set the
|
|
212
|
+
override once with `/gla model=`. (2) `pi-notify-agent` notifies on every turn;
|
|
213
|
+
`/gla notify=` fires only on goal complete/pause/loop stop.
|
|
214
|
+
|
|
215
|
+
## Files
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
extensions/
|
|
219
|
+
loops/goal.ts # /goal + /list commands, agent tools, loop driver
|
|
220
|
+
goal-loop-core.ts # types, JSONL state, pure helpers
|
|
221
|
+
goal-loop-auditor.ts # isolated auditor (fresh session, no extensions)
|
|
222
|
+
goal-loop-shield.ts # regression_shield (pure, dependency-free)
|
|
223
|
+
goal-loop-display.ts # status line + /goal status rendering
|
|
224
|
+
goal-loop-forever.ts # /loop measure/parse/plateau helpers
|
|
225
|
+
goal-loop-backoff.ts # 5-min hard cap
|
|
226
|
+
prompts/
|
|
227
|
+
goal-loop-continuation.md # loop driver prompt
|
|
228
|
+
goal-loop-draft.md # drafting prompt
|
|
229
|
+
goal-loop-forever.md # /loop driver prompt
|
|
230
|
+
goal-loop-forever-draft.md # /loop drafting prompt
|
|
231
|
+
scripts/
|
|
232
|
+
smoke.sh # live integration harness (tmux + real models)
|
|
233
|
+
tests/ # 150 unit tests, no live pi required
|
|
234
|
+
docs/DESIGN.md # architectural decisions
|
|
235
|
+
PLAN.md # milestones, decisions, gates
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Detailed design
|
|
239
|
+
|
|
240
|
+
See `docs/DESIGN.md`. Milestones and decisions live in `PLAN.md`.
|
|
241
|
+
|
|
242
|
+
## Installation from source
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
git clone https://github.com/DraconDev/pi-goal-list-loop-audit.git
|
|
246
|
+
cd pi-goal-list-loop-audit
|
|
247
|
+
pi install .
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT
|
package/docs/DESIGN.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# pi-goal-list-loop-audit — design
|
|
2
|
+
|
|
3
|
+
This document records the architectural choices and why. v0.1.0 decisions are
|
|
4
|
+
below; later releases append addenda rather than rewrite history.
|
|
5
|
+
|
|
6
|
+
## Scope
|
|
7
|
+
|
|
8
|
+
| Loop | Status |
|
|
9
|
+
|---|---|
|
|
10
|
+
| Loop 1 (single ordered goal with auditor) | **shipped v0.1.0** |
|
|
11
|
+
| Loop 2 (list — many goals in a queue) | **shipped v0.2.0** |
|
|
12
|
+
| Loop 3 (loop — metric-driven forever) | **shipped v0.3.0** |
|
|
13
|
+
| Completion release (compaction, token guard, branch mode) | **shipped v0.4.0** |
|
|
14
|
+
|
|
15
|
+
## Addendum v0.2.0 (list + shield + drafting)
|
|
16
|
+
|
|
17
|
+
- **`/list` queue**: items are full goals (objective + contract). The active
|
|
18
|
+
goal and the queue share one `State`; `setGoal`/`archiveCurrentGoal`
|
|
19
|
+
preserve `state.list` explicitly (an early draft wiped it). Completing a
|
|
20
|
+
list-sourced goal auto-activates the next item (v0.10.0: aborts no longer
|
|
21
|
+
auto-advance — `/list next` and `list_activate` pick explicitly).
|
|
22
|
+
- **regression_shield**: the auditor's report must contain an `<evidence>`
|
|
23
|
+
block quoting raw tool output per verification-contract item. Enforcement is
|
|
24
|
+
**orchestrator-side** (`goal-loop-shield.ts`, pure): an `<approved/>`
|
|
25
|
+
without complete evidence becomes a disapproval. This closes the
|
|
26
|
+
"`bash true` rubber-stamp" hole pi-goal-x documented as accepted-risk.
|
|
27
|
+
- **Drafting**: `/goal` with no args sends a drafting prompt; the agent
|
|
28
|
+
clarifies, then `propose_goal_draft` opens a real Confirm dialog. Direct
|
|
29
|
+
activation stays available via `/goal "<objective>"`.
|
|
30
|
+
- **Inline contract extraction**: one-liner objectives
|
|
31
|
+
(`Create x. Done when: grep -q ok x`) extract the contract — the
|
|
32
|
+
line-start-only extractor silently disarmed the shield on every one-liner.
|
|
33
|
+
|
|
34
|
+
## Addendum v0.3.0 (metric loop + tasks + notify)
|
|
35
|
+
|
|
36
|
+
- **Loop 3 is metric-driven, not vibes-driven** (the anti-doorknob law: the
|
|
37
|
+
loop only believes a number). The **orchestrator** runs the user's `measure`
|
|
38
|
+
command after every `agent_end`; the agent never self-reports. Termination:
|
|
39
|
+
plateau (`window` stalls), iteration cap, `/loop stop`. No auditor in
|
|
40
|
+
loop 3 — the metric is the verdict. No git auto-revert: on regression the
|
|
41
|
+
agent is told to undo its own change (safe with uncommitted user work).
|
|
42
|
+
- **`propose_task_list`** with anti-drift caps (20 tasks / 5 subtasks) —
|
|
43
|
+
pi-goal-x flaw #4. Confirm dialog before the list is set.
|
|
44
|
+
- **`notify=<cmd>`**: fire-and-forget shell-out on goal complete / goal pause /
|
|
45
|
+
loop stop, message as `$1`. Settings parser is quote-aware.
|
|
46
|
+
|
|
47
|
+
## Addendum v0.4.0 (completion)
|
|
48
|
+
|
|
49
|
+
- **Auditor compaction enabled** (flaw #3 — the last open one). Safety:
|
|
50
|
+
the shield is orchestrator-side, so compaction can only weaken the
|
|
51
|
+
auditor's evidence → disapproval, never a false approval.
|
|
52
|
+
- **Token guard**: real accumulation from assistant-message `usage.totalTokens`
|
|
53
|
+
(deduped across replayed `agent_end` history). Crossing `tokenlimit`
|
|
54
|
+
(default 1M) pauses the goal with a clear reason.
|
|
55
|
+
- **Loop 3 `branch=1`**: scratch branch `pi-gla-loop/<ts>-<slug>`; commit per
|
|
56
|
+
improvement, `git reset --hard` per regression — scratch branch only.
|
|
57
|
+
Refuses non-git dirs and dirty trees; returns to the original branch on
|
|
58
|
+
stop with merge instructions.
|
|
59
|
+
- **Resumption notice** on `session_start` (replaces the impossible
|
|
60
|
+
"plugin vanished" self-check: absent code cannot run).
|
|
61
|
+
|
|
62
|
+
## Scope of v0.1.0 (original)
|
|
63
|
+
|
|
64
|
+
Single loop only — **loop 1**, the single ordered goal.
|
|
65
|
+
|
|
66
|
+
**Why ship loop 1 first**: the user asked for it, it's the highest-value loop, and getting the auditor + drafting right matters more than breadth.
|
|
67
|
+
|
|
68
|
+
## Architectural decisions
|
|
69
|
+
|
|
70
|
+
### Decision 1: Anti-bamboozle via isolated auditor
|
|
71
|
+
|
|
72
|
+
The single most important property of this plugin is that the implementing agent cannot bamboozle the verifier. The way to achieve this structurally:
|
|
73
|
+
|
|
74
|
+
1. The auditor runs in a **fresh pi agent session**.
|
|
75
|
+
2. The auditor has **no extensions, no skills, no prompts, no themes**.
|
|
76
|
+
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).
|
|
77
|
+
4. The auditor **cannot see the implementing conversation**.
|
|
78
|
+
|
|
79
|
+
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**.
|
|
80
|
+
|
|
81
|
+
### Decision 2: regression_shield in v0.2.0
|
|
82
|
+
|
|
83
|
+
v0.1.0 ships the same auditor behaviour as pi-goal-x. The author of pi-goal-x documented an honest caveat (verbatim):
|
|
84
|
+
|
|
85
|
+
> "the guarantee is deliberately just 'the auditor ran at least one successful tool', not 'it inspected the right content': there is no cheap, honest way to tell a requirement-relevant `read` from `bash true`, an empty `grep`, or a read of an executor-planted file."
|
|
86
|
+
|
|
87
|
+
We accept this caveat for v0.1.0. v0.2.0 will add **regression_shield**: an explicit requirement that the auditor's report must include raw output (a `cat`, a `grep -A 5 <file>`, a `bash <user-script>`) for every item in `verificationContract`. Without that evidence, the auditor's `<approved/>` is rejected by the orchestrator.
|
|
88
|
+
|
|
89
|
+
### Decision 3: Hard 5-minute backoff cap
|
|
90
|
+
|
|
91
|
+
The #1 complaint about pi-goal-x in our audit (user-stated) was "1-hour waits". The cause is exponential backoff with no ceiling.
|
|
92
|
+
|
|
93
|
+
v0.1.0 ships a hard 5-minute cap. After 5 minutes of consecutive backoff:
|
|
94
|
+
1. TUI badge turns red with "Last activity: 5m+".
|
|
95
|
+
2. User can press `r` to force-continue or `s` to skip to next pending task.
|
|
96
|
+
3. Optional: configure Telegram/web push notification.
|
|
97
|
+
|
|
98
|
+
### Decision 4: No drafting phase in v0.1.0 (deferred to v0.2.0)
|
|
99
|
+
|
|
100
|
+
The user identified vague-correction as a key strength of pi-goal-x. But shipping it in v0.1.0 doubles the scope and we won't get the auditor right if we split focus.
|
|
101
|
+
|
|
102
|
+
v0.1.0 ships `/goal "<objective>"` only — same UX as pi-goal-x's `/goal-set`. v0.2.0 adds the drafting protocol with structured `goal_questionnaire` widget.
|
|
103
|
+
|
|
104
|
+
This is a deliberate trade-off. If the user wants drafting in v0.1.0, say so and I'll prioritise.
|
|
105
|
+
|
|
106
|
+
### Decision 5: One package per loop (not three packages)
|
|
107
|
+
|
|
108
|
+
Some alternatives considered:
|
|
109
|
+
- Three packages: `pi-goal-list-loop-audit`, `pi-goal-list-loop-audit-list`, `pi-goal-list-loop-audit-loop`.
|
|
110
|
+
- One package with three subcommands: `/goal`, `/pi-gla-list`, `/pi-gla-loop`.
|
|
111
|
+
|
|
112
|
+
We choose **one package with subcommands**. Reasoning:
|
|
113
|
+
- Single install (`pi install npm:pi-goal-list-loop-audit`).
|
|
114
|
+
- All three loops share state machine, schemas, scaffolding.
|
|
115
|
+
- v0.1.0 only ships loop 1, but the package already declares loop 2 and loop 3 as `pi.commands` so users see what is coming.
|
|
116
|
+
|
|
117
|
+
### Decision 6: Forks pi-goal-x rather than reimplements
|
|
118
|
+
|
|
119
|
+
Why not write from scratch?
|
|
120
|
+
- The auditor pattern is sound and small (one function: `runGoalCompletionAuditor`).
|
|
121
|
+
- The drafting phase logic is sound and small.
|
|
122
|
+
- The continuation loop is sound and small.
|
|
123
|
+
- The compaction discipline is battle-tested.
|
|
124
|
+
|
|
125
|
+
We fork pi-goal-x 0.19.0 source. We then **simplify by removing the broken parts** (markdown summaries, unbounded backoff) and **clean the seams** (split the single `goal.ts` file into per-loop files).
|
|
126
|
+
|
|
127
|
+
This is a **clean break** by decision of the user. We do not interop with `pi-goal-x`'s `.pi/goals/` directory.
|
|
128
|
+
|
|
129
|
+
### Decision 7: Per-loop file split (superseded)
|
|
130
|
+
|
|
131
|
+
> **Superseded by consolidation (v0.8.0).** The planned per-loop files below
|
|
132
|
+
> never shipped: loops 1+2 live together in `extensions/loops/goal.ts`
|
|
133
|
+
> (one state machine, one loop driver), loop 3's helpers in
|
|
134
|
+
> `extensions/loops/forever.ts`, rendering in `goal-loop-display.ts`,
|
|
135
|
+
> drafting inline in `goal.ts` + `prompts/`. Kept for history.
|
|
136
|
+
|
|
137
|
+
| File | Purpose | Lines |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `extensions/loops/goal.ts` | Loops 1+2 (single goal + list of goals) | shipped |
|
|
140
|
+
| `extensions/loops/forever.ts` | Loop 3 (metric loop helpers) | shipped |
|
|
141
|
+
| `extensions/goal-loop-core.ts` | Shared state machine, types, JSONL | shipped |
|
|
142
|
+
| `extensions/goal-loop-auditor.ts` | Isolated auditor with regression_shield | shipped |
|
|
143
|
+
| `extensions/goal-loop-display.ts` | Status line + /goal status rendering | shipped |
|
|
144
|
+
| `prompts/goal-loop-continuation.md` | Templated continuation prompt | ~80 |
|
|
145
|
+
| `prompts/goal-loop-auditor.md` | Templated auditor prompt | ~80 |
|
|
146
|
+
| `prompts/goal-loop-draft.md` | Templated drafting prompt | v0.2.0 |
|
|
147
|
+
| `schemas/goal.schema.json` | JSON Schema for goal state | ~50 |
|
|
148
|
+
|
|
149
|
+
### Decision 8: Status machine
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
type Status =
|
|
153
|
+
| "drafting" // v0.2.0
|
|
154
|
+
| "active"
|
|
155
|
+
| "auditing"
|
|
156
|
+
| "complete"
|
|
157
|
+
| "paused"
|
|
158
|
+
| "aborted";
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
States owned by the orchestrator:
|
|
162
|
+
- `active` → next iteration
|
|
163
|
+
- `auditing` → auditor running
|
|
164
|
+
- `complete` → archived
|
|
165
|
+
- `paused` → user-resumable
|
|
166
|
+
- `aborted` → user-cancelled
|
|
167
|
+
|
|
168
|
+
Transitions:
|
|
169
|
+
```
|
|
170
|
+
drafting → active (user confirms draft)
|
|
171
|
+
active → active (continue work)
|
|
172
|
+
active → auditing (complete_goal called)
|
|
173
|
+
auditing → complete (auditor <approved/>)
|
|
174
|
+
auditing → active (auditor <disapproved/>; reset iteration counter)
|
|
175
|
+
active → paused (pause_goal called, or stuck > 5 min, or empty turn)
|
|
176
|
+
paused → active (user /pi-gla-resume)
|
|
177
|
+
active → aborted (user /pi-gla-cancel)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Decision 9: JSONL state (deterministic compaction)
|
|
181
|
+
|
|
182
|
+
Goal state lives in `.pi-gla/active.jsonl`. Each line is a state transition. On compaction, the summary is rebuilt deterministically from the JSONL (autoresearch pattern).
|
|
183
|
+
|
|
184
|
+
This protects against model-generated summaries losing fidelity.
|
|
185
|
+
|
|
186
|
+
### Decision 10: Hard pause + escape hatches
|
|
187
|
+
|
|
188
|
+
| Trigger | Action |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `Esc` during auditor | Pause; user picks "complete without audit" or "continue" |
|
|
191
|
+
| `Esc` during agent turn | Pause |
|
|
192
|
+
| User `/pi-gla-pause` | Pause |
|
|
193
|
+
| User `/pi-gla-cancel` | Abort (wipes active goal) |
|
|
194
|
+
| Stuck > 5 min | Pause + notify |
|
|
195
|
+
| Empty turn (no tool calls) | Pause (no momentum) |
|
|
196
|
+
|
|
197
|
+
## Open follow-ups (post-v0.1.0)
|
|
198
|
+
|
|
199
|
+
| Priority | Item | When |
|
|
200
|
+
|---|---|---|
|
|
201
|
+
| HIGH | Drafting phase with structured Q&A | v0.2.0 |
|
|
202
|
+
| HIGH | regression_shield for auditor | v0.2.0 |
|
|
203
|
+
| MEDIUM | Native TUI form widget | v0.2.0 |
|
|
204
|
+
| MEDIUM | Loop 2 (list) | v0.2.0 |
|
|
205
|
+
| MEDIUM | Loop 3 (loop) | v0.3.0 |
|
|
206
|
+
| LOW | Telegram push | v0.3.0 |
|
|
207
|
+
| LOW | Sub-task auto-close | v0.3.0 |
|
|
208
|
+
|
|
209
|
+
## Files
|
|
210
|
+
|
|
211
|
+
- `docs/DESIGN.md` — **this file**
|
|
212
|
+
- `README.md` — quickstart
|
|
213
|
+
- `audit/pi-name-v3-registry-based.md` — naming rationale
|
|
214
|
+
- `audit/pi-goal-loop-design.md` — earlier design (now superseded)
|