A subagent runs pi -p --no-session with extensions on, so it loaded pi-goals, got the
parent's plan injected, and could sign off the parent's goals. Two windows on one checkout
also stomped each other's file. The session id in the name fixes both, and doubles as the
on switch: no /goals means no file at this session's path, so nothing fires.
Drops the v1 goals.md rename, and /goals clear now deletes the file.
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
v2 injected the entire plan.md on every turn. pi-tasks tried that and deleted it -- "wallpaper
noise that trains the model to ignore the task block" (CHANGELOG.md:149) -- so follow them: one
transient user message via the context hook, never persisted, and only when the plan went untouched
for 2 turns. Editing the plan resets the clock, the way a task tool call resets theirs. Session
start and session_compact push the WHOLE file back instead, which is where the settled context is
actually needed (pi-goal-x does the same with its post-compaction resync).
That makes an unlimited appendix free: everything under ## Log is durable memory, not working set.
Also: the drafting prompt is sent once with the /goals seed instead of every turn (that re-arming
is why plan mode read as never-ending), the review menu gains "Open in $EDITOR" and loops like
pi-plan's, and the widget shows the active goal's open subtasks so the plan is visibly the task
list. Drops the stale-copy stripping hook, which a non-persisted injection doesn't need.
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
Re-running verify was fine for 'npm test' but a footgun for ML workflows where verify may be a
10-hour training run -- and bash made 'read-only' nominal anyway (it could mutate). The agent now
runs verify itself and saves the output as evidence. The judge checks, in order: anything here /
quoted+attributed / provenance / quotes match disk / substance. Matches the cooperative-but-
confused threat model: reading real artifacts catches confusion; execution only defended against
deliberate forgery, which is out of scope.
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
Dogfood exit interview: agent bookkeeping is the drift point (tick after accept was the
step most likely forgotten), and 'committed artifact' language implied the judge sees HEAD.
Tick is exact-subject match via the existing GOAL_LINE regex; on drift the result explicitly
asks the agent to tick, so neither path is silent.
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
CompleteGoal.execute now delegates to a pure decideSignOff(input, signal,
runJudgeFn) that takes an injected judge runner. judgeModel is never checked
pre-emptively: null just omits --model (buildJudgeArgs), so pi's configured
default runs the judge. The only producers of accepted_inconclusive are now the
judge-error and no-VERDICT paths -- i.e. 'the judge ran but failed', never 'no
model'. Wording (log/result/docstring/README) updated to say 'ran but failed'.
Adds test/decide-signoff.test.ts: null judgeModel still reaches runJudge (no
pre-emptive return); judge error/timeout/no-VERDICT -> accepted_inconclusive
with a 'ran but failed' reason. 11 tests pass, typecheck + lint clean.
The v1 lesson: the parser existed so TypeScript could read goals.md, but every
reader is a model. v2 injects .pi/plan.md verbatim each turn, teaches the format
as a convention, and hands the whole file to the judge, which now does the goal
matching (tolerates wording drift), evidence validation, verify execution, and
format reading that v1 did in code. 1874 -> 530 lines.
Deleted: plan-file.ts + tests, JSON-stream judge transport, custom tool
rendering, review menu + $EDITOR + newSession dance, pruneCompleted, unwired
continuation/loopJudge prompts, MUTATING_BASH_PATTERNS. CompleteGoal's only
write is the ## Log sign-off line (the audit trail); the agent ticks [x] itself.
Judge runs with --no-extensions so a broken global extension can't take down
sign-offs (pi-hermes-memory currently does exactly that). File renamed
goals.md -> plan.md.
UAT (real judge subprocess on a toy repo, /tmp/claude-goals-uat/judge-*.log):
accept with verify run + byte-check, reject on placeholder evidence + missing
file, accept under drifted goal wording.
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
Two space-savers for a display that grows across sessions:
- widget header now carries the clickable .pi/goals.md path (with title),
dropping the separate muted footer -- one vertical line instead of two.
- /goals clear now offers 'Prune completed goals' (pure pruneCompleted:
drops done+cancelled goal blocks, keeps active/open, title, and the log)
alongside the existing full clear. Gives a way to shed old goals without
losing the audit trail.
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
Replace done_when with a discriminator + subtle-failure-mode pair as the
heart of each goal. The discriminator is the POSITIVE success observation
that no failure mode could fake, not just failure-avoidance: a run can
dodge every trap and still produce nothing. Carried through planDrafting,
the sign-off judge, README, and the parser doc.
Format migration: flat numbered markdown goals (`1. [/] goal: ...`),
keyword-anchored parsing (indentation cosmetic), goals matched by text,
subtask states [ ]/[/]/[x]/[-] plus ~~strike~~. Evidence empty at
planning, filled at sign-off, multi-line supported.
CompleteGoal now returns the judge's reasoning under a
`--- sign-off judge ---` block (was just "Signed off"), so the verdict is
visible. Plan mode is read-only: edit/write (except goals.md) and
mutating bash are blocked by a tool hook.
17 parser tests, typecheck + biome clean.
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
Goal state moves from a `status:` line into a checkbox on the goal header
(single source of truth, renders natively): [ ] open, [/] active, [x] done,
[-] cancelled. Only CompleteGoal writes [x]; the agent sets [/] when starting.
The GoalStatus enum and all consumers (widget, injection, counts) are unchanged.
Evidence becomes a goal field, not an ephemeral tool argument: an `evidence:`
block the agent fills before sign-off, read by CompleteGoal from the file
(git-tracked, reviewable). The tool is now CompleteGoal(goal_id) only.
Also:
- format reorder: subtasks under the goal; failure_modes + evidence as
separated trailing blocks (no abutting dash-lists)
- widget: (done/total tasks), and done goals show checked instead of hiding
- drafting prompt: guard against a circular done_when (one that points at the
file's own checkbox/log, which the sign-off writes, so it can never pass)
- drafting template now includes the H1 and the <!-- id --> line CompleteGoal
needs to locate a goal
- strip ANSI/CSI control codes from the judge subprocess output
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
Small, guide-not-gate plan/goal tracker for pi. The agent edits plan.md with
its normal Edit tool; CompleteGoal is the one blessed path that runs verify +
a read-only judge and records the result. Plan mode drafts goals (done_when +
failure_modes + subtasks), a per-turn injection keeps the active goal alive
through compaction, and a reminder drives upkeep + autonomy.
- src/plan-file.ts: pure parse + the two writes CompleteGoal needs + recordSignOff
- src/index.ts: plan mode, review menu, injection, reminder, widget, CompleteGoal, oracle spawn
- src/prompts.ts: all model-facing text in flow order
- test/: 15 unit tests (parser, disambiguation, sign-off record logic)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>