@jnardiello/pi-advisor
v0.1.0
Published
A second-model turn reviewer for pi: silently critiques each settled agent run and delivers severity-tagged notes on the next user turn — never generating extra turns.
Readme
pi-advisor
A "second model" turn reviewer for pi.
After every agent run settles, pi-advisor sends a compact transcript of that run to a
configured advisor model and emits its critique as nit / concern / blocker notes.
Notes are delivered with sendMessage(deliverAs: "nextTurn"), so they ride the next user
input — zero extra turns are ever generated.
How it works
- On
agent_endthe run's messages are captured (kept only in memory). - On
agent_settled(so auto-retry/compaction/follow-ups are finished) a compact transcript is built: role + text per message, tool calls with args (~200 chars), tool results (~300 chars), hard cap ~30k chars. Runs without ~200 chars of assistant text are skipped. - A subprocess runs
pi -p --no-session --no-extensions --no-skills --no-prompt-templates --no-themes --no-context-files --no-tools --model <model> "<prompt>"(async, fire-and-forget, 120s timeout). The model must answer with a JSON array only. - Output is parsed tolerantly (code fences/prose stripped, first JSON array), each item is validated, over-long notes are truncated, and malformed items are quarantined.
- Notes are filtered by
minSeverity, capped atmaxNotesPerTurn(blockers first), and deduplicated for the session. - Every note is appended as an
advisor-notesession entry and sent as a customadvisor-notemessage (deliverAs: "nextTurn"). Only wheninterruptBlockersis on and the note is a blocker is it also shown immediately viaui.notify(...)— never as a steer, which would create a spontaneous turn while idle.
Config
In ~/.pi/agent/settings.json under the advisor key (or via /advisor):
{
"advisor": {
"enabled": true,
"model": "openai/gpt-4o-mini",
"minSeverity": "concern",
"maxNotesPerTurn": 2,
"interruptBlockers": false
}
}| Key | Default | Meaning |
|-----|---------|---------|
| enabled | false | Master switch (dormant when off). |
| model | (unset) | Advisor model provider/model. Missing ⇒ dormant. |
| minSeverity | concern | Drop notes below this: nit < concern < blocker. |
| maxNotesPerTurn | 2 | Max notes delivered per turn (blockers prioritized). |
| interruptBlockers | false | Also pop a desktop-level warning for blockers. |
Commands
/advisor # status
/advisor on | off # enable / disable
/advisor model <provider/model> # set advisor model
/advisor severity <nit|concern|blocker>
/advisor maxnotes <n> # positive integer
/advisor interrupt on | off # blocker interruptionAll commands persist to settings.json atomically (temp file + rename), like pi's own
settings writes.
Privacy
To produce notes, pi-advisor sends the current run's transcript to the configured
advisor model (*"advisor"*).model). Only the run's messages travel — never the entire
session, credentials, or config — but the model provider sees that transcript. Disable
with advisor: { "enabled": false } or remove the model key.
