- Judge gets read, bash, grep, find, ls but edit+write are blocked via --exclude-tools - Added renderCall: shows goal name while running - Added renderResult: shows accept/reject icon, model, duration, collapsed/expanded view - Wired onUpdate through decideSignOff -> runJudge so the TUI shows progress while judging - Added SignOffDetails type for structured metadata - Added 120s timeout on judge subprocess
pi-goals
Plan mode for agreeing on goals before any code gets written. Each goal names the subtle failure mode that could fake a "done" and the discriminator that tells real success from it, plus subtasks and the evidence checked at sign-off. It lives in one markdown file. A widget keeps the goals in front of you through compaction, a reminder nudges the agent to keep the file current, and a goal is signed off only after a read-only subagent checks its evidence.
Like pi-milestones and burneikis/pi-plan, it guides rather than guards: a form and a process the agent follows. pi-lgtm was my earlier, more complex attempt.
Install
pi install npm:@wassname2/pi-goals
Or run it without installing:
pi -e npm:@wassname2/pi-goals
Use
/goals CSV export for the report view
/goals enters plan mode and starts a conversation; the description is an optional seed, so plain
/goals works too. From there:
- Plan. The agent explores read-only, asks about anything unclear, and writes the goals into
.pi/goals.md. - Review. You get a menu: Ready, Edit (ask the agent to revise), Open in
$EDITOR, or Cancel. On Ready you choose whether to keep the current context or start fresh and compacted. - Work. Each turn the active goal is injected so it survives compaction, and a reminder nudges the
agent to keep
goals.mdcurrent and keep going. When a goal's discriminator is satisfied the agent callsCompleteGoal, which runsverifyand a read-only judge, then marks the goal done and logs it.
Other commands: /goals clear empties .pi/goals.md; /goals judge <model-ref> picks a specific
model for the sign-off judge (the default is your current model).
Example
/goals audit the papers dir metadata and clean up empty dirs
The agent explores read-only, drafts the goal with a subtle failure mode and the discriminator that beats it, and stops for review:
## Goals
1. [ ] goal: Audit steering/ metadata and remove empty dirs
- subtle failure mode: report written but counts are zero (resolver errored silently)
- discriminator: report shows the XXXX count before/after AND a non-zero rename count
- tasks:
1. [ ] dry-run the metadata resolve
2. [ ] remove the empty _artifacts dirs
3. [ ] write the report
- evidence:
- <empty until sign-off>
You choose Ready. The agent works the subtasks, fills evidence (each item an artifact plus a short
read of it), and calls CompleteGoal:
- evidence:
- > scripts/metadata_report.txt: XXXX 52 -> 4, 146 empty _artifacts removed
- > 48 files renamed; almost certain done, the silent-resolver failure mode is ruled out
A fresh read-only subagent re-checks the evidence against the repo and the discriminator, then returns its verdict and reasoning:
Signed off "Audit steering/ metadata and remove empty dirs". Marked done in goals.md.
--- sign-off judge ---
metadata_report.txt present; counts 52 -> 4 confirmed; rename log shows 48 renamed (not zero).
VERDICT: accept
The goals.md format
One project-local file, <cwd>/.pi/goals.md (gitignored), holds the title, a context block, the
goals, and a short append-only log. A fresh /goals draft replaces it.
# ship the cache layer
Latency target came from the SLO review; keep the existing client API.
## Goals
1. [/] goal: Implement cache layer
- subtle failure mode: cache silently bypassed, latency ok by luck
- discriminator: hit-rate > 0.8 in load-test.log (a bypass reads ~0)
- verify: pytest tests/cache -q && python bench/p95.py --max-ms 50
- tasks:
1. [x] wire cache client
2. [/] eviction policy
- evidence:
- > load-test.log: p95=41ms, hit-rate 0.93 (not bypassed)
# Future work / out of scope
- distributed cache
## Log
- 2026-06-15 14:02 cache client wired; eviction next
- A goal is a numbered checkbox line beginning
goal:; the checkbox carries its state ([ ]open,[/]active,[x]done,[-]cancelled). Goals are matched by their text, so the number is just for you to reference. - The
discriminatoris the success test, written while planning: the positive observation that the goal succeeded and that none of thesubtle failure modes could fake (a count moved, a test exercised the path, a metric beat noise), not just that a failure was avoided.evidenceis the proof, filled at sign-off: each item pairs a durable artifact (a quoted and linked log, a table, a metric) with a short read of it.verify, when present, is the deterministic first stage. - Subtasks are any checkbox without a
goal:prefix, under- tasks:. The agent ticks them, appends to## Log, and sets a goal[/]when it starts it; onlyCompleteGoalwrites[x]. Several goals can be active at once.
Signing off a goal (CompleteGoal)
CompleteGoal(goal) (matched by the goal's text) is the only tool that marks a goal done; everything
else is the agent editing the file. It reads the goal's evidence: block from .pi/goals.md, then:
- If the goal has a
verify:command, it runs. A non-zero exit rejects right away, no model call. - Otherwise a read-only
pisubprocess (a fresh--no-sessioncontext, so it never sees the working agent's transcript) inspects theevidence:against the repo, thediscriminator, and thesubtle failure mode. It re-derives from the cited artifacts rather than trusting the claim, so list real artifacts, not assertions. - On accept, the goal flips to
[x]and a## Logline is written. On reject, it stays open and the agent is told what is missing. Either way the judge's reasoning comes back in the result.
The judge defaults to your current model (a fresh context, same weights). Point it at another with
/goals judge <provider/model> for an independent cross-family check.
Prompts
All model-facing text lives in src/prompts.ts, in flow order, so you can read the
whole process top to bottom.
Develop
pi -e ./src/index.ts # load locally
npm test # vitest: parser + sign-off record logic
npm run typecheck
npm run lint
Not (yet) included
- No autonomous re-prompt loop. The reminder nudges the agent within a turn, but the turn still ends and hands back to you; nothing auto-re-prompts until the goals are done.
- The plan and execution phases can't yet run on different, sticky models.
License
MIT