pi-goal-list-loop-audit

Mission control for autonomous pi: interview-drafted goals, an audited task queue, and forever-loops (metric, spec, project-audit) that run for hours. A detached extension-less auditor process re-verifies every completion with raw evidence without holding

Packages

Package details

extension

Install pi-goal-list-loop-audit from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-goal-list-loop-audit
Package
pi-goal-list-loop-audit
Version
0.35.32
Published
Aug 22, 2026
Downloads
30.4K/mo · 2,077/wk
Author
dracond
License
AGPL-3.0-only
Types
extension
Size
2.3 MB
Dependencies
0 dependencies · 5 peers
Pi manifest JSON
{
  "extensions": [
    "extensions/loops/goal.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-goal-list-loop-audit

Mission control for autonomous pi.

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.

The auditor runs in a fresh extension-less pi RPC process with no extensions, skills, prompts, themes, or context files. It has read / grep / find / ls / bash in intentional power mode. It cannot see the implementing conversation and receives no glla extension APIs or parent state handles, but bash is not an OS sandbox: a prompt-injected command or verifier can write repository/glla files or plant evidence. Its durable result is attempt-identity-checked and revalidated by the parent (including the regression shield) before it can archive a goal.

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.

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.

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.

Why this exists

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.

pi-goal-list-loop-audit separates implementation from verification. Two independent processes, two independent read paths, two perspectives.

Architectural guarantee

Stage Protection
Goal intake Deep upfront grilling + Confirm/Reject dialog; nothing activates unconfirmed
Implementation Zero-pause autonomous execution: agent_end-driven loop with autonomous pivoting & sensible defaults
Milestone gates Structured task milestones with mechanical test execution before completion
Pre-Audit Deterministic Fast-Fail: Mechanical shell checks (npm test, tsc, cargo test) run in ~200ms before spawning the auditor worker
Final Verification Detached extension-less auditor process + regression_shield: raw command output required per verification-contract item, enforced orchestrator-side
Queue Hygiene Anti-queue-drift: every single /list item receives an independent detached audit pass before queue advancement

Quick start

Install:

pi install npm:pi-goal-list-loop-audit
pi install npm:@juicesharp/rpiv-ask-user-question   # effectively required — see Recommended companions

Five top-level commands — /goal, /list, /loop, /glla, /review:

/goal                              # drafting: agent grills, you Confirm
/goal "audit the repo"             # no contract clause → agent grills you first (propose is gated on it)
/goal "Step 1. Step 2. Done when: tests pass."   # has contract → starts now
/goal start "fix the flaky login test"          # explicit skip-draft: starts now, no interview (auditor infers the contract)
/goal status                       # show state
/goal pause                        # pause
/goal resume                       # resume
/goal cancel                       # abort
/goal decide                       # re-open the decision picker (v0.28.23)
/goal audit "focus on payments"      # one-shot project audit; optional focus text
/goal verify                       # queue a detached auditor for the current goal — no agent turn (v0.28.27, renamed from /goal audit in v0.29.8)
/goal tweak "<new objective>"      # edit in place (Confirm dialog)
/goal archive                      # archived goals, newest first
/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)
/list fix the login bug, add dark mode, write docs   # dump it — the agent shapes it into items, one Confirm
/list plan.md                      # file detected → bulk import, one Confirm (sisyphus/Ralph style)
/list <paste a checklist>          # multi-line paste → same batch flow
/list "fix the flaky test. Done when: npm test green"   # explicit contract → added directly, no interview
/list                              # show the list (add/import are optional no-op aliases — detection routes everything)

(Or just say it: "queue these 10 things…" — the agent manages the list too.)

Order is the default, not the law: auto-advance takes the head (FIFO), but /list next <n> or the agent's list_activate tool picks any item — with subagents, what gets worked next is a choice, not a position. Numbering always matches /list show.

/list                              # show active + waiting items
/list next                         # skip current, activate next
/list remove <n>                   # drop item n from the list
/list clear                        # empty the list
/list cancel                       # stop the whole list: abort the active item + drop all waiting
/loop                              # draft the loop (agent grills; measure is test-run before you confirm)
/loop start "keep polishing the UI"                          # infinite metricless loop (v0.23.6): no plateau, no cap — ends at time=/tokens= or /loop stop
/loop respec                                                  # infinite metricless loop reconciling the codebase against the root SPEC.md / spec.md (v0.24.3) — 2 specs = you pick, 0 specs = drafting, 1 spec = auto-start (v0.24.4)
/loop audit                                                    # project-audit loop (v0.29.0): each iteration audits fresh, appends findings to .pi-glla/audit-loop/findings.md, fixes the top ones — the orchestrator counts open findings and the plateau stop ends it when the well is dry (one-shot version: /goal audit)
/loop start "reduce TODOs" measure="grep -c TODO src.txt | head -1" direction=min
/loop start "shrink the bundle" measure="..." direction=min time=4 tokens=500000   # arbitrary bounds
/loop start "reduce TODOs" measure="..." direction=min branch=1   # scratch-branch mode
/loop start "keep improving SPEC.md" measure=none max=20   # metricless with an explicit cap (v0.23.0)
/loop status                       # iteration, best, stall, recent values
/loop stop                         # halt with summary
/review <goal-id> [off|on|auto|aggressive]   # re-review an archived goal (bypasses the trigger gates)

Metricless loops (measure=none): for genuinely endless work — an ever-improving spec, continuous hardening — where no number means "better". There is no plateau stop (nothing to stall on): the loop ends only at its bounds (max iterations — max=0 is truly unbounded — time hours, tokens budget) or /loop stop. Every iteration must make one real, inspectable change; cosmetic churn is the known failure mode (doorknob-polishing). The drafter offers this when you say there is no number, and tells you the trade-off before you confirm. Work with a finish line is still a /goal.

Anti-repetition (v0.24.0, both loop flavors): the plateau stop watches the number; the stuck ladder watches the work. Every iteration is classified — exact/near-duplicate replies, A-B-A-B alternation, same tool-same-result three times, narration-only streaks, degenerate single-reply repetition — and a stuck iteration swaps the next prompt for a rotating intervention (different approach → different subtask → PROGRESS.md → fix one test failure → review your own diff). Three stuck in a row escalates to a hard reset (banned openings, tool-call-first); five stops the loop with the reason — bounded and surfaced, like plateau. Continuation lines also rotate: identical prompts invite identical answers.

Subcommands match exactly/goal pause the pipeline sets an objective about a pipeline; only bare /goal pause pauses. (Same rule everywhere, so your objectives can start with any verb.)

Drafting rules: no-args drafts, args-without-a-Done when:-clause get grilled by the agent (proposing is mechanically blocked until you have replied at least once — typed chat or an answered ask_user_question dialog both count), args-with-a-clause start instantly, /goal start skips the interview by explicit command, a file path is bulk direct. A sisyphus-style plan file (checklists, bullets, numbered, plain lines) imports as-is — headings become nothing, items become goals. And the drafter itself batches: asking for "these 50 tasks" in a /list drafting session produces ONE confirmed batch, not 50 dialogs. Note: every list item is audited individually, so at hundreds of items the audit cost per item is the thing to think about.

Long-running judgment is explicit: the drafter preserves the objective and verification contract, prefers a durable root-cause fix, allows a safe, reversible workaround when it is genuinely useful, and asks only at an actual scope/permission/irreversible-action decision boundary. If you want a design checkpoint before implementation, mark a goal, list item, or task-plan entry with Agent: Designer (also accepted: Role: designer or Designer: yes). The managed Designer is read-only; if it is unavailable, the main agent keeps the same checkpoint inline.

Drafting can use a separate temporary agent configured in /glla under the Drafter tab (Drafter agent, Drafter thinking, and Drafter fallback agents). The thinking choice is derived from the selected model, applies only while the drafting agent is active, and restores the original session thinking level after confirmation or interruption. A drafting failure retries the existing interview through that agent's fallback chain. Main-agent and auditor-agent recovery chains remain separate. Provider recovery is intentionally blind: there is no live quota checking or reset inference; the generic retry envelope and the optional hourly :00:30 probe remain the policy.

Drafting is the default for long-running things. /goal and /loop with no arguments — and any vague /list dump — all start a grilling turn that ends in a Confirm dialog. For /loop specifically, the orchestrator test-runs the proposed measure command once and shows the real number in the dialog — you validate the metric before a single iteration burns tokens.

With branch=1, all work lands on a scratch branch (pi-glla-loop/<ts>-<slug>): improvements are committed, regressions are hard-reset (scratch branch only), and on stop you return to your original branch with merge instructions. Requires a clean working tree.

Loop 3 is metric-driven: the orchestrator runs your measure command after every agent turn. The agent never self-reports progress — the loop only believes a number. There is no auditor in loop 3; the metric is the verdict.

A loop never completes. Goal = achievement, loop = process: there is no done= (v0.15.0 removed it — "improve until X" is a /goal). A loop runs until /loop stop, plateau (window=5 non-improving iterations — the well is dry, not "done"), max= iterations, or the arbitrary bounds time=<hours> / tokens=<budget>. And the spec is alive: mid-loop the agent can call propose_loop_refine to sharpen the target or swap the measure — you confirm, the orchestrator test-runs and re-baselines, and both eras stay in history.

Recommended companions

glla is the goal plane — it drives, verifies, and notifies. It does not try to be the whole rig. Four plugins round it out. The first is effectively required — glla's drafting interviews, DECIDE findings, and confirm dialogs are built around structured questions (it degrades to plain-text prompts without it, but that is the fallback path, not the product). The other three are optional; glla works without them:

  • @juicesharp/rpiv-ask-user-questioninstall this one. Structured questions with multi-select and markdown previews: the /goal drafting interview, DECIDE findings, and every confirm dialog render through it. Without it you get prose fallbacks — functional, but not the intended UX.
  • @tintinweb/pi-subagents — the Agent tool: parallel Explore / Plan / general-purpose subagents. glla's prompts teach fan-out with ROI (parallelize real work, never ceremony spawning) and brief discipline, and big audit collects genuinely assume this exists. glla's subagent guarantees (the main session owns the goal; workers can't clobber it) are plugin-agnostic, but this is the provider we test against.
  • @juicesharp/rpiv-advisor — a second opinion the executor model can request mid-flight: the whole conversation branch is forwarded to a stronger reviewer model, which answers with a plan, a correction, or a stop signal. Drive the session with a cheap/fast model and buy strong judgment per call. Role clarity: the advisor is advisory, never verification — glla's isolated auditor remains the only completion gate.
  • @pi-unipi/notify — push beyond the desktop: Telegram, Gotify, ntfy, with per-event routing. glla's built-in pushes cover the local desktop case and fire only where there is something to DO; add this for away-from-desk alerts — route it to critical events only, or every glla pause/verdict pings twice.

Which loop? (the decision rule)

/goal — one thing, judged semantically. Research, features, docs, anything where "done" needs a reader. The isolated auditor verifies against your Done when: contract with quoted evidence.

/list — many things, judged the same way, in turn. Bulk-import a plan or just say "queue these 10 things". Order is the default, not the law: /list next <n> picks any item.

/loop — one thing, as a process that never completes. Three flavors: metric loops (a shell command prints a number that honestly tracks progress — test failures, TODO count, bundle size, coverage %; the metric IS the auditor here, so a fake metric is worse than no loop, and the drafting step test-runs your measure and shows you the real number before you confirm), metricless spec loops (no honest number exists — the loop works a spec file with checkboxes instead; no plateau stop, ends only at your bounds or /loop stop), and /loop audit (a forever project-audit cadence that finds and fixes its own work). There is no finish line ("improve until X" is a /goal); a loop runs until you stop it, the metric plateaus, or a time/token bound trips. /loop with no args drafts one for you — and if a loop is the wrong shape entirely, drafting redirects you to /goal.

Three loops on one state machine

Loop Command Status
1. Single ordered goal /goal "<objective>" shipped v0.1.0
2. List of goals (a pool, not a FIFO) /list [show|next|remove|clear] shipped v0.2.0
3. Process loops (metric, metricless-spec, audit) /loop start|status|stop|audit shipped v0.3.0

Each loop is a different policy class on the same status machine.

What this fixes vs. pi-goal-x

Flaw in pi-goal-x Fix in pi-goal-list-loop-audit
detailedSummary is hand-concat strings Structured JSON state + native markdown renderer
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
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
pause_goal is fire-and-forget Clear pauseReason surfaced in status + agent feedback
Vague objective + weak auditor = rubber-stamp Drafting phase with Confirm dialog + isolated auditor + shield
Auditor holds the main turn open Detached worker returns control immediately; /goal cancel discards the pending claim
Auditor can't compact — context exhaustion mid-audit Compaction enabled (v0.4.0); safe because the shield is orchestrator-side
Agent can grow subtasks indefinitely propose_task_list with 20/5 caps + Confirm dialog (v0.3.0)

Live TUI (always know it's on)

A persistent glla: status segment + an above-editor widget show the current goal/list item/loop at all times: objective, durable state, elapsed time, tokens, next task or loop metric, pause reason, and live auditor progress during audits. If something is running, you can see it — no command needed. Goal cards label their total wall-clock age explicitly; it includes time parked for recovery or waiting on a verdict, so it should not be read as active model compute. Recovery cards call the timestamp last host activity for the same reason: a retry/error event is liveness evidence, not proof of useful work.

The status bar is the single activity HUD. It uses compact state capsules plus an animated pulse waveform so live work is obvious at a glance without turning the line into a progress meter. Fresh stream age is the proof of live work:

glla: [▁▂▄▆█▆ LIVE · WORKING] total 1m 09s · last stream 11s ago · 3 queued
glla: [QUEUED] 44s · 18 queued

The waveform is evidence-gated and indeterminate: it moves only while fresh stream/tool activity is present, and says nothing about completion percentage. Activity is otherwise intentionally honest:

Indicator Meaning
LIVE · WORKING Fresh stream/tool evidence is arriving; the pulse and last stream age make that visible.
BUSY pi is occupied, but no fresh stream evidence justifies a live pulse.
QUEUED A continuation is waiting to start; no work is fabricated.
IDLE The durable item remains active, but no recent work is observed.
auditor … A detached, extension-less verifier is queued, running, quiet, or waiting for its verdict.
RECOVERING A bounded automatic retry is pending; the status does not guess why the provider failed.

Detached-auditor elapsed time keeps advancing between worker events. A long tool call or hidden reasoning interval therefore remains visibly timed; after three minutes without worker activity the UI changes to auditor quiet and names the cancellation/recovery path instead of presenting a frozen live card.

Per-phase glyphs + activity meter (v0.35.15). Every auditor phase carries a distinct glyph — queued, running, quiet, blocked, awaiting-verdict — beside a draining ▰▱ activity meter, with the dense text kept as secondary detail. When a quiet stretch ends, the footer summarizes it (silent 8m then resumed) so silence is reported, not just survived. A single proactive warning fires when the detached auditor crosses the quiet threshold; it never repeats per tick.

Supervisor freeze (v0.35.15). /glla pause silences every automatic side-effect — heartbeat re-arms, recovery probes, auto-resume, auto-continuation dispatch, the proactive quiet notify, and (v0.35.17) the zero-stream auto-retry below — without touching active work or a running detached audit. The flag is persisted and survives restarts; /glla resume clears it. Bare /glla shows the frozen state.

Zombie watchdog vs subagent waits (v0.35.26, issue #13). A parent blocked on a foreground subagent call is stream-silent by design, so the zero-stream watchdog stands down while one is in flight. The recognized names cover both the built-ins (Agent, get_subagent_result, steer_subagent) and the pi-subagents extension's registrations (subagent, subagent_wait), shared by the watchdog and the wedge-alert hint so they cannot drift apart again.

Provider failures: aggressive retry envelope, bounded (v0.35.0)

Error text is not trusted to pick a retry policy. The runtime does not query or infer provider quota state, and it does not use status codes, billing words, rate-limit words, or Retry-After hints to choose a branch. Those values are retained only as bounded diagnostics. Every recoverable main-model failure uses the same durable envelope: an eager 5-second retry, then base → 2×base → 4×base → 8×base → 16×base → 5h, where base is the mainModelRetryMinutes setting (15 minutes by default). hourlyRetryProbe=on adds a blind :00:30 retry after each hour starts, so work can be picked up quickly after a possible provider-side change. The automatic window is 24h; explicit /goal resume, /list resume, or /loop resume starts a fresh window. With global autoResume=on, pending retries survive a session reload. A loop parked by the zero-stream abort (v0.35.25, issue #14) is explicitly resumable: /loop resume re-arms it with the preserved iteration count, best value, and history — exactly as the abort message promises.

Only failures identified by positive evidence as futile avoid automatic retry: context/output-token limits and user aborts (non-recoverable). Auditor watchdog timeouts are also kept separate because rerunning a hanging local verification command immediately would repeat the same local failure; the stored claim remains available for explicit resume.

For continuous work, configure up to 10 ordered Main-agent fallback models in /glla using independent model references when possible. The editor is in the Main agent settings tab (one role per tab, with the current agent, thinking level, and fallback chain together). It shows the actual try order as current → fallback 1 → fallback 2 …, shows each configured fallback's rank, lets Space add/remove a fallback, and Tab enters order mode where ↑/↓ moves the highlighted fallback (brackets [ ] also reorder without leaving the list). Every recoverable provider failure uses the same ordered chain: glla calls setModel for the first eligible fallback, the next supervised turn tests it, and later failures advance left-to-right. Forbidden, unavailable, and unauthenticated references are skipped; a successful supervised turn on a fallback proves only that fallback is healthy. By default (mainModelFailback=auto), the original primary remains durable and is probed again every mainModelPrimaryProbeMinutes (15 minutes by default); a successful supervised primary turn fails back and clears the episode. Set mainModelFailback=sticky to preserve the legacy stay-on-fallback behavior. The chain is global, durable, and its attempted cursor survives reload. After the chain is exhausted, bounded retries continue on the active model rather than silently abandoning work. The Main agent tab shows the N/10 count and numbered chain. The Drafter and Auditor tabs likewise show each selected model together with its requested thinking level; fallback rows show the effective/requested thinking level when the model registry exposes the capability map. Press d in the settings table to toggle the long descriptions and give the model/value column the available width.

Provider payloads are never copied into chat cards or notifications. A bounded diagnostic may remain in the ledger and durable state for forensics, while user-facing surfaces use the same generic provider-error label for every failure family. The detached auditor follows the same rule: every retriable infrastructure failure gets one eager 5-second retry, then stored-claim retries at :00:30 after each hour starts. Its existing 5-attempt/24-hour safety envelope prevents an unbounded worker storm; explicit resume starts a fresh window.

For long-running /list work, the card adds a compact queue trail with the immediate next item and its truthful wait age while /list remains the canonical full queue view:

● Fix the current issue · list item · active · 42m
├─ ✓ bash tests/display.test.ts (35s) · next: update docs
├─ ↳ 23 waiting · up next: refresh the release notes · waiting 12m 04s
└─ 23 queued · /list · /glla

The card does not duplicate the animated activity badge. This keeps the visual surface calm while still making a long-running list feel alive and answering the useful questions: what is active, is it really moving, and what is next?

Self-watchdog (liveness is built in)

A 15s heartbeat detects the precise stall condition — active goal/loop + idle session + nothing scheduled + quiet for 60s — and re-fires the continuation itself. Three consecutive zero-tool turns pause the goal / stop the loop. No external watchdog plugin needed. It also recovers stranded audits (v0.29.1): a goal stuck in auditing with no detached worker alive re-runs the stored claim after 90s instead of black-holing. Storm protection: the send→pause→notify path rearms once per cycle and loud-stops after a 6-error brake streak, so a broken provider can't spin forever. A confirmed queued continuation with no turn is reported by the queue-stuck probe; it does not inject terminal input.

Zero-stream zombie abort + one bounded auto-retry (v0.35.17). When pi stays BUSY with zero provider stream activity for 20 minutes, glla warns; after a 10-minute grace it aborts the zombie turn and parks the work safely. Since v0.35.17 the FIRST such silence arms exactly ONE automatic retry ~90 seconds later (the park becomes a waystation, not a dead end — field: turns dispatched by accepting Confirm dialogs hung this way repeatedly). If the retry also hangs, the second consecutive silence parks permanently for manual /goal resume / /list resume. /glla pause freezes the retry like every other automatic side-effect.

Session replacement and stale handles

Recovery crosses pi's lifecycle boundary. On session_shutdown, glla records .pi-glla/session-handoff.json for a supervising, non-quit replacement, ledgering the reason and stopping every session-owned timer. On the fresh session_start, the new context consumes only fresh, same-process debt and continues the saved goal or loop. Timers resolve a fresh context when they fire; they do not retain an old ctx or pi handle.

A user quit is not continuation consent: reason: "quit" is ledgered as session_handoff_suppressed, leaves no handoff debt, and does not receive same-pid rebind consent. An orphan with no fresh lifecycle event is reported honestly because an invalidated extension cannot repair its own pi host; use /new (or restart pi normally) and let the saved .pi-glla/ state restore. /reload does not clear pi's cached context, and event handlers cannot create a replacement session through the public pi API, so glla never claims automatic stale-session replacement. There are no automatic /reload keystrokes and no mux dependency. The legacy autoReloadOnStale and autoRecovery fields remain only as deprecated settings-file compatibility fields; they are ignored.

A stale handle never mutates (v0.34.51–v0.34.54): every /list mutation (add/remove/next/clear/cancel) and the bare /glla settings surface probe at entry and refuse with the standard recovery message on a stale extension context — a session that cannot announce or run its writes must not make them. Mutating /glla actions (wipe/cancel/reviewer/postaudit/tooloverride) leave a settings_mutation_refused_stale ledger trail; read-only surfaces (/list show, /goal status) stay usable with the warning. Once the replacement session_start arrives, both surfaces render cleanly with no stale residue (the lifecycle-recovery harness proves the two-phase contract).

User aborts mean STOP (v0.29.4): Esc-aborting a turn stands the chain down with a named notify (/goal resume to continue) — it does NOT count toward stall warnings, does NOT auto re-fire, and the stand-down survives the heartbeat (v0.29.5). Five consecutive aborts still pause loudly as a backstop. A queued steer interrupt (length/toolResult races) is not an abort and resumes normally.

One active thing (confirmed replacement)

At most one goal/list-item/loop owns the active slot. A new same-mode start never silently overwrites it: the user chooses Update current objective, Replace current objective, or Cancel new objective. Cross-mode starts offer explicit replacement/cancellation rather than silently converting a goal into a loop (or vice versa). The queued list is a backlog, not a second live thing. In headless mode, glla fails closed and asks you to resolve the existing objective explicitly instead of guessing.

Session loads still repair dirty legacy state: if a pre-guard project persisted a live loop AND a live goal, the most recent artifact keeps the slot and the loser is archived (recoverable under .pi-glla/archive/), never silently wiped. Legacy complete/aborted terminal slots are also cleared once their archive exists, while the final summary remains available in history.

Load without autostart (v0.35.23)

On startup glla RESTORES and DISPLAYS all durable state — active/paused goal, waiting queue, loop — but holds every automatic dispatch until you decide. The load hold freezes the same machinery as /glla pause (continuation dispatch, loop ticks, heartbeat refires, recovery timers) through one shared gate; unlike a manual pause it keeps host-loss supervision probing, and it is released by any explicit work command: /goal resume, /list resume, /list next, /loop resume, /loop start, or starting a new goal. Every release is ledgered (load_hold_engaged / load_hold_released). Set global Auto-resume = on to restore load-time automation for unattended rigs — the consent is the raw setting, not the aggressive-mode default. Narrow continuity exceptions keep working without consent: validated handoffs/rebinds, same-process session successors, re-arming of work already in flight when a host silently died, and the single retry a parked completion claim earns when main-model recovery heals the provider that parked it.

Due-wait backstop (v0.35.28, issue #16). A time-gated wait pause (pauseKind: "wait" with a pauseResumeAt) is no longer trusted to in-memory timers alone — agent-authored waits armed none, error-brake cooldowns were not re-armed on reload, and every scheduled resume died with its session. The heartbeat now compares wall time against pauseResumeAt every tick and re-fires the route once the deadline lapses by more than ~90s (main-model waits probe the provider; other waits clear the park and dispatch one fresh continuation). /glla pause and the load hold still freeze it; every fire is ledgered (wait_pause_overdue_resume). Auto-resumed goals carry a RECOVERY NOTICE in their next continuation prompt — "welcome back, YOU were recovered" — so the agent continues its own work instead of waiting for an external recovery signal that already fired.

Completion and destructive commands

An approved objective writes its final completion summary to the archive and shows one final ✓ done notification, then closes its live slot automatically. No follow-up cancel is required. /glla cancel stops only the active objective: for a list-owned objective it also drops the waiting queue; an unrelated standalone goal does not consume an unrelated list backlog. /glla wipe is the Confirm-gated, idempotent all-live-state reset: it preserves archive and ledger history, removes RAM state plus valid or orphaned queue sidecars, persists the clean state before optional loop-branch cleanup, and completes in one invocation. Headless /glla wipe refuses before changing state because the confirmation is intentionally not bypassed.

Config (one global place, rarely opened)

Open /glla to edit these settings in the table (the rows show effective values and provenance):

  • Auditor model and thinking level
  • Auditor fallback agent

Auditor selection (v0.35.24): the Auditor model row opens the same /model-style fuzzy picker the main agent flows use — configured-auth models only, with a session-model row and a typed escape hatch. It is at full parity with the main selector on policy too: your forbidden-models patterns filter the picker list AND a typed match is refused with a named warning, so a pin saved here is one resolveAuditorModel will actually honor. The pick lands in global auditorModel and is followed immediately by the auditor thinking dialog for that model. The Auditor fallback agent row applies the same filtering to the failure-over pin.

  • Notify command, token limit, and wedge-alert minutes
  • Auto-resume, auto-accept drafts, decision popup, and carryover policy
  • Main-agent current model/thinking, fallback models, recovery cadence, and preferred-primary failback policy in the Main agent tab
  • Drafter agent/thinking/fallback agents in the Drafter tab
  • Auditor agent/thinking/fallback agent in the Auditor tab
  • Forbidden model patterns and switch policy
  • Audit cap/report size, aggressive mode (ON by default), retry cadence, and stall brakes

The argument namespace is reserved for actions such as /glla status, /glla pause, /glla resume, /glla cancel, /glla stats, /glla audits, /glla tooloverride, /glla fallbacks clear, and /glla wipe. fallbacks clear atomically removes the global main-agent fallback chain and cancels any pending fallback switch. Pause freezes every automatic supervisor side-effect (heartbeat re-arms, recovery probes, auto-resume, continuation dispatch, loop ticks, quiet notifications) without touching active work, and survives session restarts; resume unfreezes. Cancel stops the active objective; wipe clears all live state while preserving history. There is no top-level /glla key=value setting syntax.

Resolution per key: project > global > defaults — EXCEPT autoResume and agent recovery settings (mainModelFallbacks, mainModelRetryMinutes, mainModelFailback, mainModelPrimaryProbeMinutes, drafterModel, drafterThinkingLevel, drafterModelFallbacks, hourlyRetryProbe), which are global-only: per-project opt-ins from old versions silently overrode the global hold at launch (the junk-runner incident), so the launch-restore gate and the reviewer-enqueue gate read only the global file now. Main-session recovery policy is likewise one global chain/cadence for the active session. Main-agent fallback models are global and ordered (up to 10): a provider failure selects fallback 1, then fallback 2, and so on, one supervised turn at a time. The Main agent tab leads with the ordered-chain editor — a multi-select picker where Space toggles membership, Tab enters order mode (↑/↓ moves a chain row), and clearing the selection removes the global key. Forbidden, unavailable, and unauthenticated refs are skipped. When every candidate is down, glla stops the current send attempt and uses the configured base → 2×base → 4×base → 8×base → 16×base → 5h ladder (base defaults to 15m). hourlyRetryProbe=on adds a blind :00:30 retry after each hour starts. With mainModelFailback=auto (the default), a successful fallback keeps the original primary as the preferred model and schedules a durable health probe at the mainModelPrimaryProbeMinutes cadence; the primary is selected only for a supervised probe, and a failure returns to the serving fallback. Set mainModelFailback=sticky to disable this reverse probe. No provider availability or quota check is made before any retry; all recoverable failures walk the ordered fallbacks and then continue on the active model through the bounded retry policy. Automatic recovery stops at 24h, preserves the saved work, and requires an explicit /goal resume, /list resume, or /loop resume to start a fresh window. A provider becoming available within that horizon therefore resumes saved work without manual intervention; no blind 50ms resend loop is introduced. The detached auditor uses an explicit cascade: primary auditorModel → optional fallback pin → the pi session model. If a selected model fails after launch, the worker retries it once and then advances through that same cascade; every candidate is still audited in a detached, extension-less process. There is no in-process fallback into the parent session. If the bounded cascade is exhausted, the exact completion claim is stored and the goal pauses for /goal resume; infrastructure is never treated as a verdict.

On disapproval, the executor receives the full auditor report by default (auditFeedbackChars=0, since v0.24.9 — a truncated report loses exactly the actionable tail of multi-item <evidence> blocks). Set a positive auditFeedbackChars to cap it. The complete report is always stored in audit history and is available through /goal status regardless.

autoaccept=on skips BOTH the Confirm dialog and the drafting interview floor — every propose_* draft (goal, list batch, loop, task list) activates the moment the agent proposes it, and a completed /list audit fan-out queues its generated finding items without a second confirmation. Both paths notify loudly; auto-accept is never silent. The seed carries the intent. Since v0.29.4 auto-accepted drafts start immediately — the draft path is decoupled from autoResume, which gates ONLY launch-time restore of persisted state ("load it but don't auto-start it"). For fully unattended rigs you typically want both on; for attended rigs, autoaccept=on + autoresume=off is the sweet spot (new drafts go, old state holds).

Subagents

glla's guarantees here come from glla itself (session-handle discrimination), not from any specific subagent plugin — any Agent-tool provider gets them. Subagent sessions bind extensions too, so glla loads there — by design the main session owns the goal/loop/list; subagents are workers (v0.23.8):

  • A subagent session never clobbers the loop's session handle, never runs the restore gate, and never drives continuation — so the heartbeat, wedge alert, and auto-resume machinery always act on the main session. (pi hands a fresh ctx wrapper per event; ctx.sessionManager identity is the discriminator.)
  • Subagent tool activity counts as activity for the wedge clock — a long subagent run is work, not a hang.
  • With @tintinweb/pi-subagents specifically (the one we test against): read-only agents (Explore, Plan) get no glla tools; general-purpose agents see them but state-mutating calls (complete_goal, propose_*, list_add, pause_goal, …) are refused with "report back to the main agent".

Token guard

Every goal tracks real token usage; crossing the budget pauses the goal. Off by default (opt-in) — set Token limit in the /glla settings table. A high value like 10000000 is a runaway threshold, not a big-goal threshold (real research/feature goals legitimately burn 2-4M). Loop 3 doesn't need this cap — it has its own brakes (max iterations + plateau).

Wedge alert

The turn-based watchdogs can't see one failure shape: the session is busy but silent for a long stretch because ONE unbounded command (a test suite that never exits, a dev server) is holding the whole goal hostage. The heartbeat watches the wall clock: busy + no activity for 30 minutes → in-session warning + your configured notify push, once per interval while it persists. Tune Wedge alert minutes in the /glla settings table (0 = off).

Every other wait is bounded too: continuation retries are milliseconds, nudge accounting counts consecutive unproductive turns (substantive text or tool calls reset the counter) and pauses the goal / stops the loop after 3 — provider-error and user-abort turns are exempt (v0.27.3+). Measure commands get a 10m hard timeout, and the detached auditor aborts after 10m with no activity while no an auditor tool is running. A long-running verification tool is allowed to finish, but each tool has an independent five-minute ceiling and the worker has a 30m wall-clock safety cap. Both paths are infrastructure errors, never verdicts; interrupted claims remain stored for a direct retry after /goal resume.

Compatibility (what goes well, what conflicts)

The Two-Driver Rule: any plugin that drives agent turns on agent_end conflicts — two supervisors scheduling continuations into one session produce contradictory turns. One driver at a time:

  • Hard conflicts (do not install together): pi-codex-goal, pi-loop-mode, pi-goal-x, pi-goal*, ralphi, pi-ralph*, pi-autoresearch (active).
  • Overlap: @badliveware/pi-compaction-continue — our heartbeat covers stalls while a goal/list/loop is active; both installed may double-nudge.
  • Installed-but-don't-run-simultaneously: @tmustier/pi-ralph-wiggum — fine to keep, never run a ralph loop while a goal/list/loop is active.

Goes well with it: see Recommended companions above. pi-chrome too (the research/search path for goals — logged-in browsing with no extra services; standalone search skills like mmx-cli/pi-search-skill are optional conveniences for bulk queries, not requirements).

Overlaps — pick one: @tintinweb/pi-tasks is a second task list next to /list, and in practice the glla list is the task list (queue, statuses, per-item audit trail) while the todos end up the weaker copy. We ran both and removed pi-tasks. If you truly need session-wide dependency DAGs beyond one ordered queue, it exists — but installing both is not the ideal combo.

Two footnotes: (1) extension-registered providers work in the main session but not the auditor's extension-less session — if audits fail auth, choose an auditor model in /glla settings. (2) pi-notify-agent notifies on every turn; glla pushes fire only where there is something to DO (pauses, verdicts, storms, wedge) and work out of the box — with no notify command configured glla auto-detects notify-send/osascript; notify=off silences, notify='<cmd>' customizes.

Files

Post-decomposition layout (the v0.34.x monolith is gone — loops/goal.ts is a thin activation/wiring installer):

extensions/
  goal-commands.ts             # /goal + /list command surface, drafting, wipe/stats
  loops/goal.ts                # public activation/wiring installer (thin)
  loops/goal-tools.ts          # agent tools (complete_goal, pause_goal, list_*, loop drafts)
  loops/goal-orchestrator.ts   # goal lifecycle: create/archive/advance, reviewer
  loops/goal-auditor-hooks.ts  # completion-audit claim/recovery machinery
  loops/goal-activation.ts     # event wiring, command registration, session lifecycle
  loops/goal-settings-ui.ts    # settings editors + model pickers
  goal-loop-core.ts            # types, JSONL state, pure helpers
  goal-loop-auditor.ts         # auditor prompt + legacy in-process helper
  goal-loop-auditor-process.ts # detached worker protocol + shield revalidation
  goal-loop-shield.ts          # regression_shield (pure, dependency-free)
  goal-loop-display.ts         # widget/status rendering (incl. last-outcome retention)
  goal-heartbeat.ts            # heartbeat self-watchdog, subagent probes, due-wait backstop
  goal-continuation.ts         # continuation scheduling/dispatch + prompts
  goal-recovery.ts             # main-model recovery + completion-audit recovery
  goal-loop.ts                 # Loop 3 machinery: /loop tick engine, git finish
  goal-loop-forever.ts         # /loop measure/parse/plateau helpers
  goal-loop-backoff.ts         # scheduling constants + stall/wedge/pending-latch decisions
prompts/
  goal-loop-continuation.md    # continuation prompt
  goal-loop-draft.md           # drafting prompt
  goal-loop-forever.md         # /loop driver prompt
  goal-loop-forever-draft.md   # /loop drafting prompt
scripts/
  goal-auditor-worker.mjs      # extension-less RPC auditor child process
  goal-auditor-launch.mjs      # Windows-safe spawn spec builder (gate-before-quote)
  smoke.sh                     # live integration harness (tmux + real models)
tests/                         # current test count is reported by `bun test`; no live pi required for the suite
docs/DESIGN.md                 # architectural decisions
PLAN.md                        # milestones, decisions, gates

Detailed design

See docs/DESIGN.md. Milestones and decisions live in PLAN.md.

Installation from source

git clone https://github.com/DraconDev/pi-goal-list-loop-audit.git
cd pi-goal-list-loop-audit
pi install .

Publishing for other users

The npm package is public, but publishConfig.access=public does not publish it by itself. Maintainers should configure npm Trusted Publishing for .github/workflows/publish.yml, run npm run release:check, push a matching v<version> tag, and publish a GitHub Release. That workflow then runs the full checks and npm publish --provenance --access public without a long-lived npm token. See docs/RELEASING.md; verify the result with npm view pi-goal-list-loop-audit version dist-tags.latest before telling users to upgrade.

License

GNU Affero General Public License v3.0 (AGPL-3.0-only); see LICENSE.